# Go 連接 MySQL之 MySQL 預處理 ## 一、ChatGPT 關於 MySQL 預處理 的回答 ### 問:什麼是MySQL 的預處理 具體執行過程時什麼 #### ChatGPT 答: MySQL的預處理是一種在執行SQL語句之前,先進行編譯和優化的機制。它將SQL語句分成兩個階段: ...
Go 連接 MySQL之 MySQL 預處理
一、ChatGPT 關於 MySQL 預處理 的回答
問:什麼是MySQL 的預處理 具體執行過程時什麼
ChatGPT 答:
MySQL的預處理是一種在執行SQL語句之前,先進行編譯和優化的機制。它將SQL語句分成兩個階段:預處理階段和執行階段。
具體的執行過程如下:
- 預處理階段:
- 應用程式發送SQL語句給MySQL伺服器,將其中的參數部分用占位符(如?)代替,形成一個預處理語句。
- MySQL伺服器對預處理語句進行解析、編譯和優化。
- 在這個階段,MySQL會檢查語法的正確性,創建執行計劃,以及進行許可權驗證等。
- 執行階段:
- 在預處理完成後,應用程式可以多次執行這個預處理語句,每次執行時只需提供具體的參數值。
- 應用程式將具體的參數值綁定到預處理語句的占位符上。
- MySQL伺服器使用綁定的參數值執行預處理語句,並返回執行結果。
預處理的好處包括:
- 提高執行效率:預處理語句只需要編譯一次,後續的執行可以重覆使用,避免了每次執行都要重新解析和編譯的開銷。
- 防止SQL註入:通過使用參數化查詢,將參數值與SQL語句分開處理,可以防止惡意用戶利用輸入數據進行SQL註入攻擊。
- 簡化參數處理:預處理語句可以通過占位符來接收參數,避免了手動拼接SQL語句的繁瑣和潛在的錯誤。
總結而言,MySQL的預處理是一種提前編譯和優化SQL語句的機制,它將SQL語句分為預處理和執行兩個階段,提高了執行效率和安全性,並簡化了參數處理過程。
問:Go實現MySQL預處理
ChatGPT 答:
在 Go 中,可以使用官方提供的 database/sql
包來實現 MySQL 的預處理。下麵是一個示例代碼,展示瞭如何在 Go 中進行 MySQL 預處理:
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "username:password@tcp(hostname:port)/database")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 準備預處理語句
stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
// 執行預處理語句
name := "John"
age := 30
_, err = stmt.Exec(name, age)
if err != nil {
log.Fatal(err)
}
fmt.Println("Insert successful!")
}
在上述代碼中,我們使用 sql.Open
函數建立與 MySQL 資料庫的連接。然後使用 db.Prepare
函數準備預處理語句,其中 SQL 語句中的參數位置用占位符 ?
表示。接下來,通過 stmt.Exec
函數執行預處理語句,並傳入具體的參數值。最後,我們在 main
函數中進行了錯誤處理,並列印了插入成功的消息。
請確保在代碼中填入正確的 MySQL 連接信息(用戶名、密碼、主機名、埠號和資料庫名),以便與目標資料庫建立連接。同時,請根據實際的預處理語句和參數進行適當的修改。
註意:上述示例代碼僅演示了預處理的基本流程,並沒有包含完整的錯誤處理和其他功能。在實際應用中,建議加入適當的錯誤處理、事務處理等機制,以確保代碼的健壯性和安全性。
問:MySQL預處理適用於什麼場景?
ChatGPT 答:
MySQL預處理適用於以下場景:
- 執行頻繁的重覆查詢:如果應用程式需要多次執行相同的SQL查詢,但只是參數值不同,預處理可以減少伺服器的工作量。預處理語句只需要編譯一次,後續的執行可以重覆使用,避免了每次都重新解析和編譯SQL語句的開銷。
- 參數化查詢:當需要執行帶有參數的查詢時,預處理可以提高安全性並防止SQL註入攻擊。通過使用參數化查詢,將參數值與SQL語句分開處理,可以確保輸入數據被正確地轉義和處理,避免惡意用戶利用輸入數據進行攻擊。
- 提高性能:預處理可以在編譯和優化階段對SQL語句進行處理,生成更高效的執行計劃。這可以提高查詢的性能和響應時間,特別是對於複雜查詢或涉及大量數據的查詢。
- 簡化參數處理:預處理語句可以通過占位符(如?)來接收參數值,避免了手動拼接SQL語句的繁瑣和潛在的錯誤。同時,使用預處理語句可以直接將參數值綁定到占位符上,而無需手動轉義和處理參數值。
總結而言,MySQL預處理適用於需要執行重覆查詢、參數化查詢、提高性能和簡化參數處理的場景。它可以減少伺服器的工作量,提高查詢的安全性和性能,並簡化代碼的編寫和維護。
二、Go 實現 MySQL 預處理
查詢
package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql" // 匿名導入 自動執行 init()
)
var db *sql.DB
func initMySQL() (err error) {
//DSN (Data Source Name)
dsn := "root:12345678@tcp(127.0.0.1:3306)/sql_test"
// 註意:要初始化全局的 db 對象,不要新聲明一個 db 變數
db, err = sql.Open("mysql", dsn) // 只對格式進行校驗,並不會真正連接資料庫
if err != nil {
return err
}
// Ping 驗證與資料庫的連接是否仍處於活動狀態,併在必要時建立連接。
err = db.Ping()
if err != nil {
fmt.Printf("connect to db failed, err: %v\n", err)
return err
}
// 數值需要根據業務具體情況來確定
db.SetConnMaxLifetime(time.Second * 10) // 設置可以重用連接的最長時間
db.SetConnMaxIdleTime(time.Second * 5) // 設置連接可能處於空閑狀態的最長時間
db.SetMaxOpenConns(200) // 設置與資料庫的最大打開連接數
db.SetMaxIdleConns(10) // 設置空閑連接池中的最大連接數
return nil
}
type user struct {
id int
age int
name string
}
// 預處理查詢
func prepareQueryDemo(id int) {
sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
stmt, err := db.Prepare(sqlStr)
if err != nil {
fmt.Printf("prepare failed, err: %v\n", err)
return
}
defer stmt.Close()
rows, err := stmt.Query(id)
if err != nil {
fmt.Printf("query failed, err: %v\n", err)
return
}
defer rows.Close()
// 迴圈讀取結果集中的數據
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("scan failed, err: %v\n", err)
return
}
fmt.Printf("id: %d name: %s age: %d\n", u.id, u.name, u.age)
}
}
func main() {
if err := initMySQL(); err != nil {
fmt.Printf("connect to db failed, err: %v\n", err)
}
// 檢查完錯誤之後執行,確保 db 不為 nil
// Close() 用來釋放資料庫連接相關的資源
// Close 將關閉資料庫並阻止啟動新查詢。關閉,然後等待伺服器上已開始處理的所有查詢完成。
defer db.Close()
fmt.Println("connect to database success")
// db.xx() 去使用資料庫操作...
// MySQL預處理查詢多行數據
prepareQueryDemo(0)
}
運行
Code/go/mysql_demo via