Làm việc với Cơ sở dữ liệu SQL trong Go

Trong bài viết này, tôi liệt kê cách thực hiện các thao tác cơ sở dữ liệu SQL phổ biến với Go.

Giới thiệudatabase/sql

Go cung cấp một API cơ sở dữ liệu SQL sạch trong thư viện tiêu chuẩn của nódatabase/sqlnhưng các trình điều khiển cơ sở dữ liệu cụ thể phải được cài đặt riêng.

Đó là một cách tiếp cận thông minh vì nó cung cấp một giao diện chung mà gần như mọi trình điều khiển DB đều triển khai.

Nếu bạn muốn sử dụng MySQL, bạn có thể sử dụnghttps://github.com/go-sql-driver/mysql.

Nếu bạn đang sử dụng PostgreSQL, hãy sử dụnghttps://github.com/lib/pq.

Bạn chỉ cần bao gồm lib bằng cách sử dụngimport _, vàdatabase/sqlAPI sẽ được định cấu hình để kích hoạt trình điều khiển đó:

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

Mở kết nối cơ sở dữ liệu

Mặc dù mục tiêu là trừu tượng hóa nó, nhưng vẫn có sự khác biệt trong một số điều, ví dụ như cách bạn kết nối với cơ sở dữ liệu:

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

//… db, err := sql.Open(“mysql”, “theUser:[email protected]/theDbName”) if err != nil { panic(err) }

import “database/sql”
import _ github.com/lib/pq

//… db, err := sql.Open(“postgres”, “user=theUser dbname=theDbName sslmode=verify-full”) if err != nil { panic(err) }

nhưng phần lớn API thực tế là độc lập với db và có thể được thay thế cho nhau khá dễ dàng (không nói về SQL ở đây, chỉ đề cập đến API cơ sở dữ liệu).

Đóng kết nối cơ sở dữ liệu

Nếu nó có ý nghĩa, bạn nên luôn đóng kết nối cơ sở dữ liệu.

Bạn có thể sử dụng như bình thườngdeferđể đóng nó khi chức năng mở kết nối db kết thúc:

db, err := sql.Open("postgres", psqlInfo)
defer db.Close()

Trích xuất dữ liệu từ cơ sở dữ liệu

Chọn một hàng

Truy vấn một bảng được thực hiện trong 2 bước. Đầu tiên bạn gọidb.QueryRow(), sau đó bạn gọiScan()về kết quả.

Thí dụ:

id := 1
var col string
sqlStatement := `SELECT col FROM my_table WHERE id=$1`
row := db.QueryRow(sqlStatement, id)
err := row.Scan(&col)
if err != nil {
    if err == sql.ErrNoRows {
        fmt.Println("Zero rows found")
    } else {
        panic(err)
    }
}

db.QueryRow()được sử dụng để truy vấn một giá trị duy nhất từ một bảng.

Chữ ký:

func (db *DB) QueryRow(query string, args ...interface{}) *Row

Nó trả về một con trỏ đến mộtdb.Rowgiá trị.

(*Row) Scanquét hàng, sao chép các giá trị cột thành tham số được truyền vào đó.

Chữ ký:

func (r *Row) Scan(dest ...interface{}) error

Nếu trả về nhiều hơn một hàng, nó chỉ quét hàng đầu tiênvà bỏ qua phần còn lại.

Nếu không có hàng nào được trả về, nó sẽ trả về mộtErrNoRowslỗi.

var ErrNoRows = errors.New("sql: no rows in result set")

Chọn nhiều hàng

Để truy vấn một hàng, chúng tôi đã sử dụngdb.QueryRow(). Để truy vấn nhiều hàng, chúng tôi sử dụngdb.Query(), trả về một*Rowsgiá trị.

Từ các tài liệu:

//Rows is the result of a query. Its cursor starts before  the first row of the result set. Use Next to advance through the rows:

    rows, err := db.Query("SELECT ...")
    ...
    defer rows.Close()
    for rows.Next() {
        var id int
        var name string
        err = rows.Scan(&id, &name)
        ...
    }
     err = rows.Err() // get any error encountered ing iteration
    ...

// Err trả về lỗi, nếu có, đã gặp phải trong quá trình lặp. // Err có thể được gọi sau khi đóng một cách rõ ràng hoặc ẩn.

Chúng ta cần lặp lạirows.Next(), cho phép chúng tôi gọirows.Scan()vào vòng lặp.

Nếu bất kỳ lỗi nào phát sinh khi chuẩn bị hàng tiếp theo, vòng lặp kết thúc và chúng ta có thể nhận được lỗi bằng cách gọirows.Err():

type Timeline struct {
    Id int
    Content string
}
rows, err := db.Query(`SELECT id, content FROM timeline`)
if err != nil {
    panic(err)
}
defer rows.Close()
for rows.Next() {
    timeline := Timeline{}
    err = rows.Scan(&timeline.Id, &timeline.Content)
    if err != nil {
        panic(err)
    }
    fmt.Println(timeline)
}
err = rows.Err()
if err != nil {
    panic(err)
}

Các hướng dẫn về go khác: