存取關聯式資料庫
本教學介紹了如何使用 Go 和標準函式庫中的 database/sql 套件存取關聯式資料庫的基礎知識。
如果你對 Go 及其工具鏈有基本的了解,你將能從本教學中獲得最大收益。如果你是第一次接觸 Go,請參閱 教學:Go 入門 以快速了解。
你將使用的 database/sql 套件包含了用於連接資料庫、執行事務、取消正在進行的操作等的型別和函數。有關使用該套件的更多詳細資訊,請參閱 存取資料庫。
在本教學中,你將建立一個資料庫,然後撰寫程式碼來存取該資料庫。你的範例專案將是一個關於復古爵士唱片的資料儲存庫。
在本教學中,你將經歷以下部分:
- 為程式碼建立一個資料夾。
- 設定資料庫。
- 匯入資料庫驅動。
- 取得資料庫控制代碼並連接。
- 查詢多行。
- 查詢單行。
- 加入資料。
先決條件
- MySQL 關聯式資料庫管理系統 (DBMS) 的安裝。
- Go 的安裝。 有關安裝說明,請參閱 安裝 Go。
- 一個用於編輯程式碼的工具。 任何你擁有的文字編輯器都可以正常工作。
- 一個命令終端。 Go 在 Linux 和 Mac 上的任何終端上都能很好地工作,在 Windows 上的 PowerShell 或 cmd 上也是如此。
為程式碼建立一個資料夾
首先,為要撰寫的程式碼建立一個資料夾。
-
開啟命令提示符並切換到你的主目錄。
在 Linux 或 Mac 上:
在 Windows 上:
在本教學的其餘部分,我們將顯示
$作為提示符。我們使用的命令在 Windows 上也能工作。 -
從命令提示符,建立一個名為
data-access的程式碼目錄。 -
在此教學中,你將管理要加入的依賴項,因此建立一個模組。
執行
go mod init命令,給它你新程式碼的模組路徑。此命令建立一個
go.mod檔案,其中將列出你加入的依賴項以進行追蹤。有關更多資訊,請務必參見 管理依賴項。注意: 在實際開發中,你將指定一個更具體符合你自己需求的模組路徑。有關更多資訊,請參閱 管理依賴項。
接下來,你將建立一個資料庫。
設定資料庫
在此步驟中,你將建立要使用的資料庫。你將使用 DBMS 本身的 CLI 來建立資料庫和表,以及加入資料。
你將建立一個包含關於黑膠唱片上的復古爵士錄音資料的資料庫。
這裡的程式碼使用 MySQL CLI,但大多數 DBMS 都有自己的 CLI,功能相似。
-
開啟一個新的命令提示符。
-
在命令列上,登入到你的 DBMS,如以下 MySQL 範例所示。
-
在
mysql命令提示符下,建立一個資料庫。 -
切換到剛剛建立的資料庫,以便你可以加入表。
-
在你的文字編輯器中,在
data-access資料夾中,建立一個名為create-tables.sql的檔案,用於儲存加入表的 SQL 腳本。 -
將以下 SQL 程式碼貼上到檔案中,然後儲存檔案。
在此 SQL 程式碼中,你:
-
刪除(drop)一個名為
album的表。首先執行此命令,可以讓你在以後想要重新開始表時更容易重新執行腳本。 -
建立一個包含四列的
album表:title、artist和price。每行的id值由 DBMS 自動建立。 -
加入四行值。
-
-
從
mysql命令提示符,執行你剛剛建立的腳本。你將使用以下形式的
source命令: -
在你的 DBMS 命令提示符下,使用
SELECT語句驗證你是否已成功建立帶有資料的表。
接下來,你將撰寫一些 Go 程式碼進行連接,以便你可以查詢。
查詢並匯入資料庫驅動
現在你已經有了帶有資料的資料庫,開始你的 Go 程式碼。
查詢並匯入一個資料庫驅動,該驅動將你在 database/sql 套件中透過函數發出的請求翻譯成資料庫能理解的請求。
-
在你的瀏覽器中,瀏覽 SQLDrivers wiki 頁面,以確定你可以使用的驅動。
使用該頁面上的列表來確定你將使用的驅動。在本教學中,為了存取 MySQL,你將使用 Go-MySQL-Driver。
-
記下驅動的套件名 —— 在這裡是
github.com/go-sql-driver/mysql。 -
使用你的文字編輯器,在之前建立的
data-access目錄中建立一個用於撰寫 Go 程式碼的檔案,並將其儲存為main.go。 -
將以下程式碼貼上到
main.go中,以匯入驅動套件。在這段程式碼中,你:
-
將你的程式碼加入到
main套件中,以便你可以獨立執行它。 -
匯入 MySQL 驅動
github.com/go-sql-driver/mysql。
-
匯入了驅動後,你將開始撰寫存取資料庫的程式碼。
取得資料庫控制代碼並連接
現在撰寫一些 Go 程式碼,讓你透過資料庫控制代碼存取資料庫。
你將使用指向 sql.DB 結構的指標,該結構表示對特定資料庫的存取。
撰寫程式碼
-
在
main.go中,緊接在你剛加入的import程式碼下方,貼上以下 Go 程式碼以建立資料庫控制代碼。在這段程式碼中,你:
-
宣告一個類型為
*sql.DB的db變數。這是你的資料庫控制代碼。將
db設為全域變數簡化了這個範例。在生產環境中,你應避免使用全域變數,例如透過將變數傳遞給需要它的函數或將其包裝在結構體中。 -
使用 MySQL 驅動的
Config結構體及其FormatDSN方法來收集連接屬性,並將其格式化為連接字串的 DSN。Config結構體使程式碼比連接字串更易讀。 -
呼叫
sql.Open初始化db變數,傳遞FormatDSN的返回值。 -
檢查
sql.Open的錯誤。如果資料庫連接細節格式不正確,它可能會失敗。為簡化程式碼,你呼叫
log.Fatal來終止執行並將錯誤列印到主控台。在生產程式碼中,你應以更優雅的方式處理錯誤。 -
呼叫
DB.Ping確認連接資料庫是否有效。執行時,sql.Open可能不會立即連接,具體取決於驅動。你在此使用Ping來確認database/sql套件在需要時可以連接。 -
檢查
Ping的錯誤,以防連接失敗。 -
如果
Ping成功連接,則列印一條訊息。
-
-
在
main.go檔案的頂部,緊接在套件宣告下方,匯入你剛撰寫程式碼所需的套件。檔案頂部現在應如下所示:
-
儲存
main.go。
執行程式碼
-
開始將 MySQL 驅動模組作為依賴項進行追蹤。
使用
go get將github.com/go-sql-driver/mysql模組加入為你自己的模組的依賴項。使用點參數表示「取得目前目錄中程式碼的依賴項」。因為你將驅動加入到了之前的
import宣告中,Go 下載了這個依賴項。有關依賴項追蹤的更多資訊,請參閱 加入依賴項。 -
從命令提示符,設定
DBUSER和DBPASS環境變數,供 Go 程式使用。在 Linux 或 Mac 上:
在 Windows 上:
-
在包含
main.go的目錄的命令列中,透過鍵入go run並使用點參數(表示「執行目前目錄中的套件」)來執行程式碼。
你已成功連接!接下來,你將查詢一些資料。
查詢多行
在本節中,你將使用 Go 執行旨在返回多行的 SQL 查詢。
對於可能返回多行的 SQL 語句,你使用 database/sql 套件中的 Query 方法,然後循環遍歷它返回的行。(你將在後面的 查詢單行 部分學習如何查詢單行。)
撰寫程式碼
-
在
main.go中,緊接在func main上方,貼上以下Album結構體定義。你將用它來儲存查詢返回的行資料。 -
在
func main下方,貼上以下albumsByArtist函數以查詢資料庫。在這段程式碼中,你:
-
宣告一個你定義的
Album類型的albums切片。這將儲存返回行中的資料。結構體欄位名稱和類型對應資料庫列名稱和類型。 -
使用
DB.Query執行SELECT語句,查詢具有指定藝術家名稱的專輯。Query的第一個參數是 SQL 語句。在參數之後,你可以傳遞零個或多個任何類型的參數。這些參數為你於 SQL 語句中指定的參數值提供位置。透過將 SQL 語句與參數值分開(而不是用fmt.Sprintf拼接),你使database/sql套件能夠將值與 SQL 文本分開發送,消除 SQL 注入風險。 -
延遲關閉
rows,以便在函數退出時釋放它持有的任何資源。 -
循環遍歷返回的行,使用
Rows.Scan將每行的列值分配給Album結構體欄位。Scan接受一個指向 Go 值的指標列表,列值將寫入這些值。在這裡,你傳遞使用&運算子建立的alb變數中的欄位指標。Scan透過這些指標寫入以更新結構體欄位。 -
在循環內,檢查將列值掃描到結構體欄位時發生的錯誤。
-
在循環內,將新的
alb追加到albums切片。 -
在循環後,使用
rows.Err檢查整體查詢的錯誤。注意,如果查詢本身失敗,檢查此處的錯誤是唯一能發現結果不完整的方法。
-
-
更新你的
main函數以呼叫albumsByArtist。在
func main的結尾,加入以下程式碼。在新程式碼中,你現在:
-
呼叫你加入的
albumsByArtist函數,將其返回值分配給一個新的albums變數。 -
列印結果。
-
執行程式碼
在包含 main.go 的目錄的命令列中,執行程式碼。
接下來,你將查詢單行。
查詢單行
在本節中,你將使用 Go 查詢資料庫中的單行。
對於你知道最多返回單行的 SQL 語句,你可以使用 QueryRow,它比使用 Query 循環更簡單。
撰寫程式碼
-
在
albumsByArtist下方,貼上以下albumByID函數。在這段程式碼中,你:
-
使用
DB.QueryRow執行SELECT語句,查詢具有指定 ID 的專輯。它返回一個
sql.Row。為了簡化呼叫程式碼(你的程式碼!),QueryRow不返回錯誤。相反,它安排稍後從Rows.Scan返回任何查詢錯誤(例如sql.ErrNoRows)。 -
使用
Row.Scan將列值複製到結構體欄位。 -
檢查
Scan的錯誤。特殊錯誤
sql.ErrNoRows表示查詢未返回任何行。通常,這個錯誤值得用更具體的文本替換,例如這裡的「no such album」。
-
-
更新
main以呼叫albumByID。在
func main的結尾,加入以下程式碼。在新程式碼中,你現在:
-
呼叫你加入的
albumByID函數。 -
列印返回的專輯 ID。
-
執行程式碼
在包含 main.go 的目錄的命令列中,執行程式碼。
接下來,你將向資料庫加入一張專輯。
加入資料
在本節中,你將使用 Go 執行 SQL INSERT 語句,向資料庫加入新行。
你已經了解了如何使用 Query 和 QueryRow 執行返回資料的 SQL 語句。要執行 不 返回資料的 SQL 語句,你使用 Exec。
撰寫程式碼
-
在
albumByID下方,貼上以下addAlbum函數以在資料庫中插入新專輯,然後儲存main.go。在這段程式碼中,你:
-
使用
DB.Exec執行INSERT語句。像
Query一樣,Exec接受 SQL 語句,後跟 SQL 語句的參數值。 -
檢查嘗試
INSERT的錯誤。 -
使用
Result.LastInsertId檢索插入資料庫行的 ID。 -
檢查嘗試檢索 ID 的錯誤。
-
-
更新
main以呼叫新的addAlbum函數。在
func main的結尾,加入以下程式碼。在新程式碼中,你現在:
- 使用新專輯呼叫
addAlbum,將你要加入的專輯 ID 分配給albID變數。
- 使用新專輯呼叫
執行程式碼
在包含 main.go 的目錄的命令列中,執行程式碼。
結論
恭喜!你剛剛使用 Go 對關聯式資料庫執行了簡單的操作。
建議的後續主題:
-
查看資料存取指南,其中包含有關此處僅簡要提及主題的更多資訊。
-
如果你是 Go 新手,你會在 Effective Go 和 如何撰寫 Go 程式碼 中發現有用的最佳實踐。
-
Go 教學 是 Go 基礎的逐步介紹。
完整程式碼
本節包含你透過本教學建立的應用程式的程式碼。