ZetCode

Go sqlite3

最后修改时间 2024 年 4 月 11 日

在本文中,我们将展示如何在 Golang 中使用 sqlite3 数据库。这些示例执行基本的数据库操作。

SQLite 是一个嵌入式关系数据库引擎。其文档称它是一个独立、无服务器、零配置和事务性的 SQL 数据库引擎。它非常受欢迎,目前全球有数亿份副本在使用。

Go 提供了 sql 包,该包提供了 SQL(或类 SQL)数据库的通用接口。sql 包必须与数据库驱动程序一起使用。

创建 SQLite 数据库

我们可以使用 sqlite3 命令行工具创建数据库和查询数据。

$ sudo apt install sqlite3

我们安装该工具。

$ sqlite3 test.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite>

我们向 sqlite3 工具提供一个参数;test.db 是数据库名称。它是在我们磁盘上的一个文件。如果文件存在,它将被打开。如果不存在,它将被创建。

sqlite> .tables
sqlite> .exit
$ ls
test.db

.tables 命令会列出 test.db 数据库中的表。目前没有表。.exit 命令会终止 sqlite3 命令行工具的交互式会话。ls 命令显示当前工作目录的内容。我们可以看到 test.db 文件。所有数据将存储在这个单一文件中。

Go sqlite3 版本

在第一个示例中,我们打印 sqlite3 的版本。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", ":memory:")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    var version string
    err = db.QueryRow("SELECT SQLITE_VERSION()").Scan(&version)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(version)
}

该程序返回 sqlite3 的版本。版本是通过执行 SELECT SQLITE_VERSION() 语句确定的。

_ "github.com/mattn/go-sqlite3"

当一个包被导入并带有空白标识符前缀时,该包的 init 函数会被调用。该函数注册驱动程序。

db, err := sql.Open("sqlite3", ":memory:")

使用 sql.Open,我们可以打开一个由其数据库驱动程序名称和特定于驱动程序的数据源名称指定的数据库。在我们的例子中,我们连接到内存数据库。

defer db.Close()

Close 函数关闭数据库并阻止新的查询开始。

err = db.QueryRow("SELECT SQLITE_VERSION()").Scan(&version)

QueryRow 执行一个预期最多返回一行的查询。Scan 函数将匹配行中的列复制到 version 变量。

$ go run main.go
3.38.5

Go sqlite3 Exec

Exec 函数执行一个不返回任何行的查询。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", "test.db")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    sts := `
DROP TABLE IF EXISTS cars;
CREATE TABLE cars(id INTEGER PRIMARY KEY, name TEXT, price INT);
INSERT INTO cars(name, price) VALUES('Audi',52642);
INSERT INTO cars(name, price) VALUES('Mercedes',57127);
INSERT INTO cars(name, price) VALUES('Skoda',9000);
INSERT INTO cars(name, price) VALUES('Volvo',29000);
INSERT INTO cars(name, price) VALUES('Bentley',350000);
INSERT INTO cars(name, price) VALUES('Citroen',21000);
INSERT INTO cars(name, price) VALUES('Hummer',41400);
INSERT INTO cars(name, price) VALUES('Volkswagen',21600);
`
    _, err = db.Exec(sts)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("table cars created")
}

在示例中,我们创建一个新表。

db, err := sql.Open("sqlite3", "test.db")

我们创建一个新的文件数据库。

    sts := `
DROP TABLE IF EXISTS cars;
CREATE TABLE cars(id INTEGER PRIMARY KEY, name TEXT, price INT);
INSERT INTO cars(name, price) VALUES('Audi',52642);
INSERT INTO cars(name, price) VALUES('Mercedes',57127);
INSERT INTO cars(name, price) VALUES('Skoda',9000);
INSERT INTO cars(name, price) VALUES('Volvo',29000);
INSERT INTO cars(name, price) VALUES('Bentley',350000);
INSERT INTO cars(name, price) VALUES('Citroen',21000);
INSERT INTO cars(name, price) VALUES('Hummer',41400);
INSERT INTO cars(name, price) VALUES('Volkswagen',21600);
`

这些是创建新表的 SQL 语句。

_, err = db.Exec(sts)

这些语句使用 Exec 执行。

Go sqlite3 使用 Query 选择所有行

Query 执行一个返回行的查询,通常是 SELECT。可选参数是查询中的任何占位符参数。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", "test.db")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    rows, err := db.Query("SELECT * FROM cars")

    if err != nil {
        log.Fatal(err)
    }

    defer rows.Close()

    for rows.Next() {

        var id int
        var name string
        var price int

        err = rows.Scan(&id, &name, &price)

        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%d %s %d\n", id, name, price)
    }
}

该示例从 cars 表中选择所有行。

rows, err := db.Query("SELECT * FROM cars")

这是选择所有行的 SQL。

for rows.Next() {

Next 方法准备好下一行结果供 Scan 方法读取。如果成功则返回 true,如果不存在下一行结果或在准备过程中发生错误则返回 false。

err = rows.Scan(&id, &name, &price)

我们将行读取到变量中。

fmt.Printf("%d %s %d\n", id, name, price)

当前行被打印出来。

$ go run main.go
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600

Go sqlite3 预编译语句

使用预编译语句,我们使用占位符而不是直接将值写入语句。预编译语句提高了数据库操作的安全性和性能。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", "test.db")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    stm, err := db.Prepare("SELECT * FROM cars WHERE id = ?")

    if err != nil {
        log.Fatal(err)
    }

    defer stm.Close()

    var id int
    var name string
    var price int

    cid := 3

    err = stm.QueryRow(cid).Scan(&id, &name, &price)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%d %s %d\n", id, name, price)
}

我们使用预编译语句来选择一个特定行。

stm, err := db.Prepare("SELECT * FROM cars WHERE id = ?")

Prepare 函数创建用于后续查询或执行的预编译语句。占位符 ? 稍后将被值填充。

err = stm.QueryRow(cid).Scan(&id, &name, &price)

传递给 QueryRow 函数的值会映射到占位符。Scan 函数将匹配行中的列复制到变量中。

$ go run main.go
3 Skoda 9000

也可以使用 QueryRow 在一步中完成预编译语句。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", "test.db")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    cid := 3

    var id int
    var name string
    var price int

    row := db.QueryRow("SELECT * FROM cars WHERE id = ?", cid)
    err = row.Scan(&id, &name, &price)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%d %s %d\n", id, name, price)
}

该示例创建一个预编译语句;这次使用的是 QueryRow

Go sqlite3 受影响的行数

RowsAffected 返回受 update、insert 或 delete 语句影响的行数。

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

func main() {

    db, err := sql.Open("sqlite3", "test.db")

    if err != nil {
        log.Fatal(err)
    }

    defer db.Close()

    res, err := db.Exec("DELETE FROM cars WHERE id IN (1, 2, 3)")

    if err != nil {
        log.Fatal(err)
    }

    n, err := res.RowsAffected()

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("The statement has affected %d rows\n", n)
}

在代码示例中,我们使用 DELETE SQL 语句删除了三行。然后我们使用 RowsAffected 打印删除的行数。

$ go run main.go 
The statement has affected 3 rows

来源

Go sqlite3 - Github 页面

在本文中,我们研究了 Go 中的 sqlite3。

作者

我叫 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程