ZetCode

Go MySQL

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

本文介绍如何使用 Golang 操作 MySQL。示例演示了基本数据库操作。

MySQL 是领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在 Web 上尤其受欢迎。MariaDB 是 MySQL 关系数据库管理系统的一个社区开发、商业支持的分支。

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

该包提供自动连接池。每次我们查询数据库时,我们使用的是应用程序启动时设置的连接池中的连接。连接会被重用。

$ go get -u github.com/go-sql-driver/mysql

我们需要安装 MySQL 驱动程序。

cities_mysql.sql
USE testdb;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);

在本教程中,我们使用 cities 表。

Go MySQL 版本

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

version.go
package main

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

    _ "github.com/go-sql-driver/mysql"
)

func main() {

    db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")
    defer db.Close()

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

    var version string

    err2 := db.QueryRow("SELECT VERSION()").Scan(&version)

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

    fmt.Println(version)
}

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

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

当一个包被导入,并且其名称前加上一个空白标识符时,该包的 init 函数会被调用。该函数会注册驱动程序。

db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")

使用 sql.Open,我们可以打开一个由其数据库驱动程序名称和特定于驱动程序的数据源名称指定的数据库,该数据源名称通常至少包含数据库名称和连接信息。它不会建立任何到数据库的连接,也不会验证驱动程序的连接参数。相反,它只是准备好数据库抽象供以后使用。与底层数据存储的第一个实际连接将在需要时惰性建立。

defer db.Close()

Close 将连接返回到连接池。如果 sql.DB 的生命周期不应该超出函数的作用域,那么 defer db.Close 是惯用做法。

err2 := db.QueryRow("SELECT VERSION()").Scan(&version)

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

$ go run version.go
10.3.24-MariaDB-2

Go MySQL 使用 Query 查询所有行

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

select_all.go
package main

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

    _ "github.com/go-sql-driver/mysql"
)

type City struct {
    Id         int
    Name       string
    Population int
}

func main() {

    db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")
    defer db.Close()

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

    res, err := db.Query("SELECT * FROM cities")

    defer res.Close()

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

    for res.Next() {

        var city City
        err := res.Scan(&city.Id, &city.Name, &city.Population)

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

        fmt.Printf("%v\n", city)
    }
}

该示例打印 cities 表中的所有行。

for res.Next() {

Next 使用 Scan 方法准备下一条结果行以供读取。成功时返回 true,如果没有下一条结果行或在准备它时发生错误,则返回 false。

err := res.Scan(&city.Id, &city.Name, &city.Population)

我们将数据读取到 City 结构体中 Scan

$ go run select_all.go
{1 Bratislava 432000}
{2 Budapest 1759000}
{3 Prague 1280000}
{4 Warsaw 1748000}
{5 Los Angeles 3971000}
{6 New York 8550000}
{7 Edinburgh 464000}
{8 Berlin 3671000}

Go MySQL 插入行使用 Exec

Exec 函数执行一个不返回行的查询。它用于 INSERT、UPDATE、DELETE 或 DROP 语句。可选参数用于查询中的任何占位符参数。

insert_row.go
package main

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

    _ "github.com/go-sql-driver/mysql"
)

func main() {

    db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")
    defer db.Close()

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

    sql := "INSERT INTO cities(name, population) VALUES ('Moscow', 12506000)"
    res, err := db.Exec(sql)

    if err != nil {
        panic(err.Error())
    }

    lastId, err := res.LastInsertId()

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

    fmt.Printf("The last inserted row id: %d\n", lastId)
}

该示例向 cities 表插入一个新行。

sql := "INSERT INTO cities(name, population) VALUES ('Moscow', 12506000)"
res, err := db.Exec(sql)

我们将一个新城市插入表中。

lastId, err := res.LastInsertId()

使用 LastInsertId,我们获取最后插入的 ID。

Go MySQL 预编译语句

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

Go 在后台为您创建预编译语句。

db.Query(sql, param1, param2)

Query 函数预编译 SQL,然后用参数执行它,最后关闭语句。

prepared.go
package main

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

    _ "github.com/go-sql-driver/mysql"
)

type City struct {
    Id         int
    Name       string
    Population int
}

func main() {

    db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")
    defer db.Close()

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

    var myid int = 1

    res, err := db.Query("SELECT * FROM cities WHERE id = ?", myid)
    defer res.Close()

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

    if res.Next() {

        var city City
        err := res.Scan(&city.Id, &city.Name, &city.Population)

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

        fmt.Printf("%v\n", city)
    } else {

        fmt.Println("No city found")
    }
}

该示例从数据库中选择一行。

res, err := db.Query("SELECT * FROM cities WHERE id = ?", myid)

? 是一个占位符,它被 myid 变量的值填充。在底层,db.Query 实际上会准备、执行并关闭一个预编译语句。

$ go run prepared.go
{1 Bratislava 432000}

Go MySQL 受影响的行数

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

affected_rows.go
package main

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

    _ "github.com/go-sql-driver/mysql"
)

func main() {

    db, err := sql.Open("mysql", "user7:s$cret@tcp(127.0.0.1:3306)/testdb")
    defer db.Close()

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

    sql := "DELETE FROM cities WHERE id IN (2, 4, 6)"
    res, err := db.Exec(sql)

    if err != nil {
        panic(err.Error())
    }

    affectedRows, err := res.RowsAffected()

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

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

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

$ go run affected_rows.go 
The statement affected 3 rows

来源

Go mysql - Github 页面

在本文中,我们已经使用 Go 语言操作了 MySQL。

作者

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

列出所有 Go 教程