sqlite以其无需安装和配置:直接使用数据库文件,无需启动独立的数据库服务进程。
单文件存储:整个数据库(包括表、索引、数据等)存储在单个跨平台文件中,便于迁移和备份。
在应对的小型应用软件中.有着不可取代的地位.
sqlite使用 参考 10.1.SQLite-CSDN博客
go语言中使用sqlite
1. 推荐使用 go-sqlite3
驱动,它基于 C 语言的 SQLite 库实现:
go get github.com/mattn/go-sqlite3
2. 连接数据库
使用 Go 标准库 database/sql
结合驱动进行操作:
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3" // 导入但不直接使用
)
func main() {
// 打开数据库连接(如果文件不存在会自动创建)
db, err := sql.Open("sqlite3", "./test.db")
if err != nil {
panic(err)
}
defer db.Close() // 程序结束时关闭连接
// 验证连接是否有效
if err := db.Ping(); err != nil {
panic(err)
}
fmt.Println("成功连接到SQLite数据库")
}
3. 创建表
使用 Exec
方法执行 SQL 语句:
// 创建表
func createTable(db *sql.DB) error {
sqlStmt := `
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER
);
`
_, err := db.Exec(sqlStmt)
return err
}
4. 插入数据
支持普通插入和预处理语句(防止 SQL 注入):
// 普通插入
func insertData(db *sql.DB, name string, age int) error {
sqlStmt := fmt.Sprintf("INSERT INTO users (name, age) VALUES ('%s', %d)", name, age)
_, err := db.Exec(sqlStmt)
return err
}
// 预处理语句插入(推荐)
func insertDataWithPrepare(db *sql.DB, name string, age int) error {
stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(name, age)
return err
}
5. 查询数据
- 单条记录:使用
QueryRow
- 多条记录:使用
Query
// 查询单条记录
func querySingleUser(db *sql.DB, id int) (string, int, error) {
var name string
var age int
err := db.QueryRow("SELECT name, age FROM users WHERE id = ?", id).Scan(&name, &age)
if err != nil {
return "", 0, err
}
return name, age, nil
}
// 查询多条记录
func queryAllUsers(db *sql.DB) ([]struct{ Name string; Age int }, error) {
rows, err := db.Query("SELECT name, age FROM users")
if err != nil {
return nil, err
}
defer rows.Close()
var users []struct{ Name string; Age int }
for rows.Next() {
var name string
var age int
if err := rows.Scan(&name, &age); err != nil {
return nil, err
}
users = append(users, struct{ Name string; Age int }{name, age})
}
// 检查迭代过程中是否有错误
if err := rows.Err(); err != nil {
return nil, err
}
return users, nil
}
6. 更新和删除数据
// 更新数据
func updateUserAge(db *sql.DB, id, newAge int) error {
stmt, err := db.Prepare("UPDATE users SET age = ? WHERE id = ?")
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(newAge, id)
return err
}
// 删除数据
func deleteUser(db *sql.DB, id int) error {
stmt, err := db.Prepare("DELETE FROM users WHERE id = ?")
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(id)
return err
}
7. 事务处理
使用事务保证数据一致性:
func transferMoney(db *sql.DB, from, to int, amount float64) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p) // 重新抛出异常
} else if err != nil {
tx.Rollback() // 发生错误时回滚
} else {
err = tx.Commit() // 提交事务
}
}()
// 执行事务操作
if _, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, from); err != nil {
return err
}
if _, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", amount, to); err != nil {
return err
}
return nil
}
8. 启用 WAL 模式
在连接字符串中添加 _journal_mode=WAL
参数:
db, err := sql.Open("sqlite3", "./test.db?_journal_mode=WAL")
SQLite 的 WAL(Write-Ahead Logging)模式是一种替代传统回滚日志(ROLLBACK JOURNAL)的事务机制,它能显著提升数据库的并发性能和写入吞吐量。
传统模式(ROLLBACK JOURNAL)
- 写操作流程:
- 将原始数据写入临时回滚日志(
.db-journal
)。 - 修改主数据库文件。
- 事务提交后删除回滚日志。
- 将原始数据写入临时回滚日志(
- 缺点:写操作时需对整个数据库加独占锁,导致读写互斥,并发性能差。
WAL 模式
- 写操作流程:
- 将修改写入独立的 WAL 文件(
.db-wal
)。 - 事务提交时,只需要写入一个 4 字节的提交标记到 WAL 文件末尾。
- 读取操作直接从主数据库和 WAL 文件合并后的状态读取。
- 将修改写入独立的 WAL 文件(
- 优点:读写操作可以并发进行(读不阻塞写,写不阻塞读)。
读写并发
- WAL 模式允许同时进行读和写操作,提升并发性能。
- 限制:同一时间只能有一个写事务,但可以有多个并发读事务。
9. 错误处理
// 检查SQL执行结果
result, err := db.Exec("INSERT INTO ...")
if err != nil {
log.Fatal(err)
}
// 获取插入ID
id, err := result.LastInsertId()
if err != nil {
log.Fatal(err)
}
// 获取受影响行数
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Fatal(err)
}
完整示例
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()
// 创建表
if err := createTable(db); err != nil {
log.Fatal(err)
}
// 插入数据
if err := insertDataWithPrepare(db, "Alice", 30); err != nil {
log.Fatal(err)
}
// 查询数据
users, err := queryAllUsers(db)
if err != nil {
log.Fatal(err)
}
fmt.Println("所有用户:", users)
// 更新数据
if err := updateUserAge(db, 1, 31); err != nil {
log.Fatal(err)
}
// 删除数据
if err := deleteUser(db, 1); err != nil {
log.Fatal(err)
}
}
注意事项
- 并发限制:SQLite 原生不支持多写操作,高并发场景需考虑锁机制或使用其他数据库。
- 文件权限:确保数据库文件所在目录可读写。
- SQL 注入:始终使用预处理语句(
Prepare
+Exec
)避免 SQL 注入。