使用 SQLite 数据库
尝试在 Windows 上使用 github.com/mattn/go-sqlite3 驱动,程序会给你以下错误
go get github.com/mattn/go-sqlite3
# github.com/mattn/go-sqlite3
exec: "gcc": executable file not found in %PATH%
go-sqlite3 是一个 cgo 包,要使用 go-sqlite3 构建应用程序,您需要使用 gcc 进行编译,但是在你使用构建和安装 go-sqlite3 之后,你以后可以构建你的应用程序而无需依赖 gcc。因此,请按顺序执行下面提到的步骤
- 从这里下载 gcc http://tdm-gcc.tdragon.net/download
- 安装 gcc
go get -u github.com/mattn/go-sqlite3
go install github.com/mattn/go-sqlite3
SQLite 增删改查实例
下面的例子显示的如何使用 go-sqlite3 进行数据库操作,结合一个 Person 结构实现了数据库的增删改查操作。
增加数据
// 添加一条数据
func addPerson(person Person) (int64, error) {
result, err := db.Exec(`INSERT INTO person (name,nickname,created_at) VALUES ($1,$2,$3)`, person.Name, person.Nickname, person.CreatedAt.Format(currentTimeStamp))
checkErr(err)
id, err := result.LastInsertId()
checkErr(err)
return id, nil
}
更新数据
// 更新一条数据(指定ID)
func updatePerson(person Person) error {
_, err := db.Exec(`UPDATE person SET name = $1,nickname = $2,created_at = $3 WHERE id = $4`, person.Name, person.Nickname, person.CreatedAt, person.ID)
checkErr(err)
return nil
}
读取数据
// 读取所有数据
func readAllPerson() ([]Person, error) {
rows, err := db.Query(`SELECT * FROM person`)
defer rows.Close()
checkErr(err)
var result []Person
for rows.Next() {
v := Person{}
err := rows.Scan(&v.ID, &v.Name, &v.Nickname, TimeStamp{&v.CreatedAt})
checkErr(err)
result = append(result, v)
}
return result, nil
}
删除数据
// 删除一条数据(指定ID)
func deletePerson(person Person) error {
_, err := db.Exec(`DELETE FROM person WHERE id = $1`, person.ID)
checkErr(err)
return nil
}
完整代码
sqlite.sql 文件
DROP TABLE person;
CREATE TABLE IF NOT EXISTS person (
id INTEGER PRIMARY KEY AUTOINCREMENT, --主键
name TEXT NOT NULL UNIQUE, --名字
nickname TEXT NOT NULL , --昵称
created_at INTEGER NOT NULL --创建时间
);
main.go 文件
package main
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3"
"io/ioutil"
"log"
"strings"
"time"
)
/*!
具体请参考 https://pkg.go.dev/github.com/lib/pq
增删查改(英语:CRUD[注 1]),全称增加(Create,意为“创建”)、删除(Delete)、查询(Read,意为“读取”)、改正(Update,意为“更新”)。
在计算机程序语言中是一连串常见的动作行为,而其行为通常是为了针对某个特定资源所作出的举动(例如:创建资料、读取资料等)。
中文 英文 中文 SQL HTTP
增加 Create 创建 INSERT PUT / POST
删除 Delete 删除 DELETE DELETE
查询 Read 读取 SELECT GET
改正 Update 更新 UPDATE PUT / POST
*/
var (
db *sql.DB // 数据库句柄
lastErr error
)
const currentTimeStamp = "2006-01-02 15:04:05Z07:00"
type TimeStamp struct {
*time.Time
}
// Scan 因 sqlite 驱动不支持扫描 time.Time 数据类型,故在此实现一个 Scan 接口以提供该功能.
func (t TimeStamp) Scan(value interface{}) error {
var err error
switch v := value.(type) {
case string:
*t.Time, err = time.Parse(currentTimeStamp, v)
case []byte:
*t.Time, err = time.Parse(currentTimeStamp, string(v))
default:
err = errors.New("invalid type for current_timestamp")
}
return err
}
func (t TimeStamp) Value() (driver.Value, error) {
return t.Time.Format(currentTimeStamp), nil
}
// Person 数据库表的结构
type Person struct {
ID int64
Name string
Nickname string
CreatedAt time.Time
}
// 添加一条数据
func addPerson(person Person) (int64, error) {
result, err := db.Exec(`INSERT INTO person (name,nickname,created_at) VALUES ($1,$2,$3)`, person.Name, person.Nickname, person.CreatedAt.Format(currentTimeStamp))
checkErr(err)
id, err := result.LastInsertId()
checkErr(err)
return id, nil
}
// 添加更多数据
func addArrayPerson(person []Person) error {
tx, err := db.Begin()
checkErr(err)
stmt, err := tx.Prepare(`INSERT INTO person (name,nickname,created_at) VALUES ($1,$2,$3)`)
checkErr(err)
defer stmt.Close()
for _, v := range person {
_, err = stmt.Exec(v.Name, v.Nickname, v.CreatedAt.Format(currentTimeStamp))
checkErr(err)
}
tx.Commit()
return nil
}
// 更新一条数据(指定ID)
func updatePerson(person Person) error {
_, err := db.Exec(`UPDATE person SET name = $1,nickname = $2,created_at = $3 WHERE id = $4`, person.Name, person.Nickname, person.CreatedAt, person.ID)
checkErr(err)
return nil
}
// 读取所有数据
func readAllPerson() ([]Person, error) {
rows, err := db.Query(`SELECT * FROM person`)
defer rows.Close()
checkErr(err)
var result []Person
for rows.Next() {
v := Person{}
err := rows.Scan(&v.ID, &v.Name, &v.Nickname, TimeStamp{&v.CreatedAt})
checkErr(err)
result = append(result, v)
}
return result, nil
}
// 读取指定 name 字段数据
func readPersonByName(person Person) (Person, error) {
row := db.QueryRow(`SELECT * FROM person WHERE name = $1`, person.Name)
v := Person{}
err := row.Scan(&v.ID, &v.Name, &v.Nickname, &v.CreatedAt)
checkErr(err)
return v, nil
}
// 删除一条数据(指定ID)
func deletePerson(person Person) error {
_, err := db.Exec(`DELETE FROM person WHERE id = $1`, person.ID)
checkErr(err)
return nil
}
// init 函数是一个包初始化函数,在 main 函数之前自动调用,此函数的主要作用是初始化不能在全局上下文中初始化的全局变量.
func init() {
db, lastErr = sql.Open("sqlite3", "./person.db")
checkErr(lastErr)
//defer db.Close()
// 测试 [1]
// 创建表 [1.1]
lastErr = createSchemaFromSQLFile("sqlite.sql", db)
checkErr(lastErr)
// 添加数据 [1.2]
person := Person{
Name: "cheungxiongwei",
Nickname: "驭鲸环球",
CreatedAt: time.Now().UTC(),
}
id, _ := addPerson(person)
// 更新数据 [1.3]
person.ID = id
person.Nickname = "cheungxiongwei"
person.CreatedAt = time.Now().UTC()
updatePerson(person)
// 查询数据 [1.4]
array, _ := readAllPerson()
for _, person := range array {
// 打印数据
log.Println(person.Name, person.Nickname, person.CreatedAt.Format(currentTimeStamp))
}
// 删除数据 [1.5]
deletePerson(person)
}
// 检查&打印错误
func checkErr(err error, args ...string) {
if err != nil {
fmt.Println("Error")
fmt.Println("%q: %s", err, args)
}
}
// 创建数据表 sql 文件中需要使用 ; 符号隔离语句
func createSchemaFromSQLFile(filename string, db *sql.DB) error {
fileByte, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
for _, s := range strings.Split(string(fileByte), ";\n") {
if s = strings.TrimSpace(s); s == "" {
continue
}
if _, err := db.Exec(s); err != nil {
return err
} else {
log.Printf(s)
}
}
return nil
}
func main() {
}