在 SQLite 中,事务(Transaction) 是确保 数据一致性 和 原子性 的核心机制。
支持 ACID 特性:原子性、一致性、隔离性、持久性。
一、事务基础语法
BEGIN [DEFERRED | IMMEDIATE | EXCLUSIVE]; -- 开始事务
-- ... SQL 语句
COMMIT; -- 提交
-- 或
ROLLBACK; -- 回滚
| 类型 | 说明 |
|---|---|
BEGIN(默认) | 等同 BEGIN DEFERRED |
BEGIN DEFERRED | 延迟锁,直到第一次写操作才锁表 |
BEGIN IMMEDIATE | 立即获取写锁,防止其他连接写入 |
BEGIN EXCLUSIVE | 独占整个数据库,读写都阻塞其他连接 |
二、事务类型对比
| 模式 | 读操作 | 写操作 | 其他连接读 | 其他连接写 | 推荐场景 |
|---|---|---|---|---|---|
DEFERRED | 可 | 延迟锁 | 可 | 可(写时冲突) | 读多写少 |
IMMEDIATE | 可 | 立即锁 | 可 | 阻塞 | 写操作需优先 |
EXCLUSIVE | 可 | 独占 | 阻塞 | 阻塞 | 批量导入、重建表 |
三、典型使用示例
1. 转账事务(原子性)
BEGIN IMMEDIATE;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 模拟错误
-- UPDATE accounts SET balance = balance + 100 WHERE id = 2;
-- 检查余额
-- SELECT RAISE(ROLLBACK, 'Insufficient funds') WHERE (SELECT balance FROM accounts WHERE id = 1) < 0;
COMMIT;
若任意一步失败,
ROLLBACK自动恢复
2. 批量插入(性能优化)
BEGIN;
INSERT INTO logs (user_id, action) VALUES (1, 'login');
INSERT INTO logs (user_id, action) VALUES (2, 'logout');
-- ... 10万条
COMMIT;
单事务比逐条提交快 10~100 倍!
3. 安全更新(IMMEDIATE)
BEGIN IMMEDIATE;
UPDATE config SET value = 'new' WHERE key = 'version';
COMMIT;
防止其他连接同时修改配置
四、自动提交模式(默认开启)
PRAGMA autocommit; -- 返回 1(开启)
- 每条 SQL 语句 默认是一个独立事务
- 显式
BEGIN后,关闭自动提交,直到COMMIT/ROLLBACK
五、保存点(Savepoint)——局部回滚
BEGIN;
INSERT INTO users (name) VALUES ('Alice'); -- 成功
SAVEPOINT sp1;
INSERT INTO users (name) VALUES (NULL); -- 违反 NOT NULL
-- 出错!
ROLLBACK TO sp1; -- 只回滚到 sp1
-- Alice 保留!
INSERT INTO users (name) VALUES ('Bob');
RELEASE SAVEPOINT sp1; -- 释放保存点
COMMIT;
类似“嵌套事务”,但 不是真嵌套
六、事务隔离级别
SQLite 只支持 SERIALIZABLE(最高隔离级别)
| 级别 | 是否支持 |
|---|---|
READ UNCOMMITTED | ❌ |
READ COMMITTED | ❌ |
REPEATABLE READ | ❌ |
SERIALIZABLE | ✅(默认) |
写冲突时,后写者失败,需重试
七、常见错误与解决
| 错误 | 原因 | 解决 |
|---|---|---|
database is locked | 写冲突 | 用 BEGIN IMMEDIATE 或重试 |
cannot rollback - no transaction | 未开启事务 | 先 BEGIN |
savepoint does not exist | 释放顺序错 | 按创建顺序 RELEASE |
八、性能优化建议
| 优化点 | 操作 |
|---|---|
| 批量操作 | 包裹在 BEGIN ... COMMIT |
| 减少锁冲突 | 缩短事务时间 |
| 大事务分段 | 用 SAVEPOINT + 定期 COMMIT |
| WAL 模式 | 提高并发 |
PRAGMA journal_mode = WAL; -- 推荐生产环境
九、WAL 模式下的并发
| 场景 | 是否允许 |
|---|---|
| 多连接同时 读 | ✅ |
| 多连接同时 写 | ⚠️ 排队,但不阻塞读 |
| 读写并发 | ✅ 高效 |
WAL = Write-Ahead Logging,比传统
ROLLBACK JOURNAL更快
十、完整实战示例:订单系统
-- 开启 WAL
PRAGMA journal_mode = WAL;
-- 事务:创建订单 + 扣库存
BEGIN IMMEDIATE;
-- 1. 创建订单
INSERT INTO orders (user_id, total) VALUES (123, 99.99);
INSERT INTO order_items (order_id, product_id, qty, price)
VALUES (last_insert_rowid(), 5, 1, 99.99);
-- 2. 扣库存
UPDATE products SET stock = stock - 1 WHERE id = 5;
-- 3. 检查库存
-- SELECT RAISE(ROLLBACK, 'Out of stock')
-- WHERE (SELECT stock FROM products WHERE id = 5) < 0;
COMMIT;
总结:事务核心要点
| 项目 | 内容 |
|---|---|
| 默认 | 自动提交(每条 SQL 一个事务) |
| 显式事务 | BEGIN ... COMMIT/ROLLBACK |
| 锁策略 | DEFERRED(默认)、IMMEDIATE、EXCLUSIVE |
| 隔离级别 | 仅 SERIALIZABLE |
| 保存点 | SAVEPOINT / ROLLBACK TO / RELEASE |
| 推荐模式 | PRAGMA journal_mode = WAL; |
快速参考卡
-- 普通事务
BEGIN; ... COMMIT;
-- 优先写锁
BEGIN IMMEDIATE; ... COMMIT;
-- 局部回滚
SAVEPOINT x; ... ROLLBACK TO x; ... RELEASE x;
-- 提高并发
PRAGMA journal_mode = WAL;
需要我帮你:
- 分析某个操作是否需要事务?
- 优化一个慢事务?
- 写一个带重试机制的转账事务?
把你的 SQL 发我!