sqlite以其无需安装和配置:直接使用数据库文件,无需启动独立的数据库服务进程。
单文件存储:整个数据库(包括表、索引、数据等)存储在单个跨平台文件中,便于迁移和备份。
在应对的小型应用软件中.有着不可取代的地位.
sqlite使用 参考 10.1.SQLite-CSDN博客
10.2sql-CSDN博客
go语言中使用sqlite
1. 推荐使用 go-sqlite3
驱动,它基于 C 语言的 SQLite 库实现:
go get github.com/mattn/go-sqlite3
2. 连接数据库
使用 Go 标准库 database/sql
结合驱动进行操作:
package mainimport ("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 stringvar age interr := 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 stringvar age intif 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 mainimport ("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 注入。