Go 语言中操作 SQLite

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)
  • 写操作流程
    1. 将原始数据写入临时回滚日志(.db-journal)。
    2. 修改主数据库文件。
    3. 事务提交后删除回滚日志。
  • 缺点:写操作时需对整个数据库加独占锁,导致读写互斥,并发性能差。
WAL 模式
  • 写操作流程
    1. 将修改写入独立的 WAL 文件(.db-wal)。
    2. 事务提交时,只需要写入一个 4 字节的提交标记到 WAL 文件末尾。
    3. 读取操作直接从主数据库和 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)}
}

注意事项

  1. 并发限制:SQLite 原生不支持多写操作,高并发场景需考虑锁机制或使用其他数据库。
  2. 文件权限:确保数据库文件所在目录可读写。
  3. SQL 注入:始终使用预处理语句(Prepare + Exec)避免 SQL 注入。