简介
此示例将研究GO语言中MySQL数据库访问的基础知识,创建数据库表,存储和读取数据。
安装go-sql-driver / mysql软件包
Go编程语言附带了一个名为database / sql
的软件包,用于查询各种SQL数据库。 这很有用,因为它将所有通用SQL功能抽象为一个API供你使用,但 Go不包括数据库驱动程序。 在Go中,数据库驱动程序是一个用于实现特定数据库底层细节的软件包(本例为MySQL)。由于无法预见哪些数据库将来都会投入使用,而支持每个可能的数据库将需要大量维护工作,因此Go语言未包含数据库驱动程序,需要额外进行安装。
要安装MySQL数据库驱动程序,只需要在终端中执行以下操作:
go get -u github.com/go-sql-driver/mysql
连接到MySQL数据库
安装所有必需的软件包后,需要检查的第一件事是,是否可以成功连接到MySQL数据库。 如果尚未运行MySQL数据库服务器,可以通过Docker轻松的启动一个实例。 这是MySQL的映像的官方Docker镜像:https://hub.docker.com/_/mysql
要检查是否可以连接到数据库,请导入数据库/ sql和go-sql-driver / mysql软件包,并按如下所示打开连接:
import "database/sql"
import _ "go-sql-driver/mysql"
// Configure the database connection (always check errors)
db, err := sql.Open("mysql", "username:password@(127.0.0.1:3306)/dbname?parseTime=true")
// Initialize the first connection to the database, to see if everything works correctly.
// Make sure to check the error.
err := db.Ping()
创建第一个数据库表
我们数据库中的每个数据条目都存储在一个特定的表中。 数据库表由列和行组成。 这些列为每个数据条目提供一个标签并指定其类型。 这些行是插入的数据值。 在我们的第一个示例中,我们想要创建一个像这样的表:
id | username | password | created_at |
---|---|---|---|
1 | johndoe | secret | 2019-08-10 12:30:00 |
创建表格的SQL命令如下:
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);
现在有了SQL命令,可以使用database/sql
包在MySQL数据库中创建表:
query := `
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);`
// Executes the SQL query in our database. Check err to ensure there was no error.
_, err := db.Exec(query)
插入第一个用户
如果你熟悉SQL,向表中插入新数据就像创建表一样容易。 需要注意的一件事是:默认情况下,Go使用准备好的语句将动态数据插入SQL查询语句中,这是一种将用户提供的数据安全地传递到数据库的方式,而不会造成任何损坏。 在Web编程的早期,程序员将带有查询的数据直接传递到数据库,这导致了巨大的漏洞,并可能破坏整个Web应用程序,请不要那样做。
要将第一个用户插入数据库表,创建一个如下的SQL查询。此处省略了id列,因为它是由MySQL自动设置的。 问号告诉SQL驱动程序,它们是实际数据的占位符。 在这里可以看到准备好的语句。
INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)
现在可以在Go中使用此语句插入用户。
import "time"
username := "johndoe"
password := "secret"
createdAt := time.Now()
// Inserts our data into the users table and returns with the result and a possible error.
// The result contains information about the last inserted id (which was auto-generated for us) and the count of rows this query affected.
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
要获取用户在数据库中最新创建的ID,只需按以下方式获取:
userID, err := result.LastInsertId()
查询用户表
现在表中有一个用户,我们想查询它并获取其所有信息。 在Go中有两种查询表的方法。 db.Query
可以迭代查询多行;还有db.QueryRow
只查询特定的行。
查询特定行的工作原理基本上与之前介绍的所有其他SQL命令一样。
SQL命令通过其ID查询单个用户,如下所示:
SELECT id, username, password, created_at FROM users WHERE id = ?
在Go中首先声明一些变量来存储数据,然后查询单个数据库行,如下所示:
var (
id int
username string
password string
createdAt time.Time
)
// Query the database and scan the values into out variables. Don't forget to check for errors.
query := `SELECT id, username, password, created_at FROM users WHERE id = ?`
err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt)
查询所有用户
前面的部分介绍了如何查询单个用户行。 而许多应用程序都有查询所有用户的应用。 这与上面的示例相似,只是涉及更多的编码。
我们可以使用上面示例中的SQL命令并修改WHERE
子句。 这样可以查询所有用户。
SELECT id, username, password, created_at FROM users
在Go中首先声明一些变量来存储数据,然后查询单个数据库行,如下所示:
type user struct {
id int
username string
password string
createdAt time.Time
}
rows, err := db.Query(`SELECT id, username, password, created_at FROM users`) // check err
defer rows.Close()
var users []user
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt) // check err
users = append(users, u)
}
err := rows.Err() // check err
user切片现在包含的内容如下:
users {
user {
id: 1,
username: "johndoe",
password: "secret",
createdAt: time.Time{wall: 0x0, ext: 63701044325, loc: (*time.Location)(nil)},
},
user {
id: 2,
username: "alice",
password: "bob",
createdAt: time.Time{wall: 0x0, ext: 63701044622, loc: (*time.Location)(nil)},
},
}
删除用户
最后,从表中删除用户与上述各节中的.Exec一样简单:
_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1) // check err
代码
package main
import (
"database/sql"
"fmt"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "root:root@(127.0.0.1:3306)/root?parseTime=true")
if err != nil {
log.Fatal(err)
}
if err := db.Ping(); err != nil {
log.Fatal(err)
}
{ // Create a new table
query := `
CREATE TABLE users (
id INT AUTO_INCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
created_at DATETIME,
PRIMARY KEY (id)
);`
if _, err := db.Exec(query); err != nil {
log.Fatal(err)
}
}
{ // Insert a new user
username := "johndoe"
password := "secret"
createdAt := time.Now()
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
if err != nil {
log.Fatal(err)
}
id, err := result.LastInsertId()
fmt.Println(id)
}
{ // Query a single user
var (
id int
username string
password string
createdAt time.Time
)
query := "SELECT id, username, password, created_at FROM users WHERE id = ?"
if err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt); err != nil {
log.Fatal(err)
}
fmt.Println(id, username, password, createdAt)
}
{ // Query all users
type user struct {
id int
username string
password string
createdAt time.Time
}
rows, err := db.Query(`SELECT id, username, password, created_at FROM users`)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var users []user
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt)
if err != nil {
log.Fatal(err)
}
users = append(users, u)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v", users)
}
{
_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1)
if err != nil {
log.Fatal(err)
}
}
}
网友评论