Bạn có thể định nghĩa một prepared statement để dùng lại nhiều lần. Điều này giúp mã của bạn chạy nhanh hơn một chút nhờ tránh được chi phí tạo lại câu lệnh mỗi lần mã thực hiện thao tác cơ sở dữ liệu.
Lưu ý: Ký hiệu chỗ dành cho tham số trong prepared statement khác nhau tuỳ theo DBMS và driver bạn đang dùng. Ví dụ, driver pq cho Postgres yêu cầu ký hiệu placeholder kiểu $1 thay vì ?.
Prepared statement là gì?
Prepared statement là câu SQL đã được DBMS phân tích cú pháp và lưu lại, thường chứa các placeholder nhưng chưa có giá trị tham số thực tế. Về sau, câu lệnh có thể được thực thi với một bộ giá trị tham số.
Cách dùng prepared statement
Khi bạn dự kiến sẽ thực thi cùng một câu SQL nhiều lần, bạn có thể dùng một sql.Stmt để chuẩn bị trước câu lệnh SQL, rồi thực thi nó khi cần.
Ví dụ dưới đây tạo một prepared statement chọn ra một album cụ thể từ cơ sở dữ liệu. DB.Prepare trả về một sql.Stmt đại diện cho một prepared statement ứng với một đoạn văn bản SQL cho trước. Bạn có thể truyền các tham số của câu lệnh SQL vào Stmt.Exec, Stmt.QueryRow, hoặc Stmt.Query để chạy câu lệnh đó.
// AlbumByID retrieves the specified album.
func AlbumByID(id int) (Album, error) {
// Define a prepared statement. You'd typically define the statement
// elsewhere and save it for use in functions such as this one.
stmt, err := db.Prepare("SELECT * FROM album WHERE id = ?")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
var album Album
// Execute the prepared statement, passing in an id value for the
// parameter whose placeholder is ?
err := stmt.QueryRow(id).Scan(&album.ID, &album.Title, &album.Artist, &album.Price, &album.Quantity)
if err != nil {
if err == sql.ErrNoRows {
// Handle the case of no rows returned.
}
return album, err
}
return album, nil
}
Hành vi của prepared statement
Một sql.Stmt đã được chuẩn bị cung cấp các method quen thuộc Exec, QueryRow, và Query để gọi câu lệnh. Tìm hiểu thêm về cách dùng các method này tại Truy vấn dữ liệu và Thực thi câu lệnh SQL không trả về dữ liệu.
Tuy nhiên, vì một sql.Stmt vốn đã đại diện cho một câu lệnh SQL định sẵn, nên các method Exec, QueryRow, và Query của nó chỉ nhận các giá trị tham số SQL tương ứng với các placeholder, mà bỏ qua phần văn bản SQL.
Bạn có thể định nghĩa một sql.Stmt mới theo nhiều cách khác nhau, tuỳ theo bạn sẽ dùng nó ra sao.
DB.PreparevàDB.PrepareContexttạo một prepared statement có thể được thực thi độc lập, tự nó và nằm ngoài transaction, giống như cáchDB.ExecvàDB.Queryhoạt động.Tx.Prepare,Tx.PrepareContext,Tx.Stmt, vàTx.StmtContexttạo một prepared statement để dùng trong một transaction cụ thể.PreparevàPrepareContextdùng văn bản SQL để định nghĩa câu lệnh.StmtvàStmtContextdùng kết quả củaDB.PreparehoặcDB.PrepareContext. Nghĩa là, chúng chuyển mộtsql.Stmtkhông dành cho transaction thành mộtsql.Stmtdành cho chính transaction này.Conn.PrepareContexttạo một prepared statement từ mộtsql.Conn, vốn đại diện cho một kết nối được giữ riêng.
Hãy bảo đảm stmt.Close được gọi khi mã của bạn đã dùng xong một câu lệnh. Việc này sẽ giải phóng mọi tài nguyên cơ sở dữ liệu (chẳng hạn các kết nối bên dưới) có thể đang gắn với nó. Với những câu lệnh chỉ là biến cục bộ trong một hàm, chỉ cần defer stmt.Close() là đủ.
Các hàm để tạo prepared statement
| Hàm | Mô tả |
|---|---|
DB.PrepareDB.PrepareContext |
Chuẩn bị một câu lệnh để thực thi độc lập, hoặc để về sau được chuyển thành prepared statement nằm trong transaction bằng Tx.Stmt. |
Tx.PrepareTx.PrepareContextTx.StmtTx.StmtContext |
Chuẩn bị một câu lệnh để dùng trong một transaction cụ thể. Tìm hiểu thêm tại Thực thi transaction. |
Conn.PrepareContext |
Dùng với các kết nối được giữ riêng. Tìm hiểu thêm tại Quản lý kết nối. |