SQLite事务 #
一、事务概述 #
1.1 什么是事务 #
sql
-- 事务是一组SQL操作,作为一个单元执行
-- 要么全部成功,要么全部失败
-- 事务的特点(ACID):
-- A - Atomicity(原子性):事务不可分割
-- C - Consistency(一致性):事务前后数据一致
-- I - Isolation(隔离性):事务之间互不干扰
-- D - Durability(持久性):事务提交后永久保存
1.2 SQLite事务特点 #
sql
-- SQLite 事务特点:
-- 1. 默认每个SQL语句是一个事务
-- 2. 支持嵌套事务(通过SAVEPOINT)
-- 3. 支持读事务和写事务
-- 4. 使用锁机制实现隔离
二、基本事务操作 #
2.1 BEGIN…COMMIT #
sql
-- 开始事务
BEGIN TRANSACTION;
-- 或简写
BEGIN;
-- 执行SQL操作
INSERT INTO users (name, email) VALUES ('John', 'john@example.com');
INSERT INTO orders (user_id, total) VALUES (last_insert_rowid(), 100);
-- 提交事务
COMMIT;
-- 或
COMMIT TRANSACTION;
2.2 ROLLBACK #
sql
-- 回滚事务
BEGIN;
INSERT INTO users (name, email) VALUES ('Test', 'test@example.com');
-- 发现错误,回滚
ROLLBACK;
-- 或
ROLLBACK TRANSACTION;
2.3 自动提交模式 #
sql
-- SQLite 默认自动提交模式
-- 每个SQL语句自动成为一个事务
-- 单条语句
INSERT INTO users (name) VALUES ('John');
-- 自动提交
-- 显式事务
BEGIN;
INSERT INTO users (name) VALUES ('John');
INSERT INTO users (name) VALUES ('Jane');
COMMIT;
-- 两条语句作为一个事务
三、事务类型 #
3.1 DEFERRED事务 #
sql
-- DEFERRED:延迟获取锁(默认)
-- 开始时不获取锁,第一次读写时获取
BEGIN DEFERRED;
-- 读操作 - 获取共享锁
SELECT * FROM users;
-- 写操作 - 获取排他锁
INSERT INTO users (name) VALUES ('Test');
COMMIT;
3.2 IMMEDIATE事务 #
sql
-- IMMEDIATE:立即获取保留锁
-- 阻止其他写事务,允许读事务
BEGIN IMMEDIATE;
-- 其他连接可以读,但不能写
INSERT INTO users (name) VALUES ('Test');
COMMIT;
3.3 EXCLUSIVE事务 #
sql
-- EXCLUSIVE:获取排他锁
-- 阻止其他所有事务
BEGIN EXCLUSIVE;
-- 其他连接不能读也不能写
INSERT INTO users (name) VALUES ('Test');
COMMIT;
3.4 事务类型对比 #
sql
-- 事务类型对比表
-- | 类型 | 开始时锁 | 允许并发读 | 允许并发写 |
-- |------------|----------|------------|------------|
-- | DEFERRED | 无锁 | 是 | 是 |
-- | IMMEDIATE | 保留锁 | 是 | 否 |
-- | EXCLUSIVE | 排他锁 | 否 | 否 |
四、SAVEPOINT #
4.1 创建保存点 #
sql
-- SAVEPOINT:嵌套事务
BEGIN;
INSERT INTO users (name) VALUES ('User1');
-- 创建保存点
SAVEPOINT sp1;
INSERT INTO users (name) VALUES ('User2');
-- 回滚到保存点
ROLLBACK TO SAVEPOINT sp1;
-- 继续操作
INSERT INTO users (name) VALUES ('User3');
-- 释放保存点
RELEASE SAVEPOINT sp1;
COMMIT;
4.2 多级保存点 #
sql
-- 多级保存点
BEGIN;
INSERT INTO users (name) VALUES ('User1');
SAVEPOINT level1;
INSERT INTO users (name) VALUES ('User2');
SAVEPOINT level2;
INSERT INTO users (name) VALUES ('User3');
-- 回滚到level2
ROLLBACK TO SAVEPOINT level2;
-- User3 被撤销
-- 回滚到level1
ROLLBACK TO SAVEPOINT level1;
-- User2 和 User3 被撤销
COMMIT;
-- 只有 User1 被提交
五、隔离级别 #
5.1 SQLite隔离级别 #
sql
-- SQLite 默认隔离级别:SERIALIZABLE
-- 支持的隔离级别:
-- 1. SERIALIZABLE(默认)
-- 2. REPEATABLE READ
-- 3. READ COMMITTED
-- SQLite 通过锁机制实现隔离
-- 不支持设置隔离级别
5.2 读一致性 #
sql
-- SQLite 保证事务内的读一致性
-- 连接1
BEGIN;
SELECT * FROM users; -- 看到某个状态
-- 连接2
INSERT INTO users (name) VALUES ('New User');
COMMIT;
-- 连接1
SELECT * FROM users; -- 仍然看到之前的状态,看不到新数据
COMMIT;
SELECT * FROM users; -- 现在可以看到新数据
六、锁机制 #
6.1 锁类型 #
text
SQLite 锁类型(从低到高):
├── UNLOCKED - 未锁定
├── SHARED - 共享锁(读)
├── RESERVED - 保留锁(准备写)
├── PENDING - 等待锁(等待其他读完成)
└── EXCLUSIVE - 排他锁(写)
6.2 锁升级 #
sql
-- 锁升级过程
-- 1. 读操作:UNLOCKED -> SHARED
-- 2. 写操作:SHARED -> RESERVED -> PENDING -> EXCLUSIVE
-- 查看当前锁状态
PRAGMA locking_mode;
-- 设置锁模式
PRAGMA locking_mode = EXCLUSIVE;
6.3 WAL模式 #
sql
-- WAL(Write-Ahead Logging)模式
-- 提高并发性能
-- 启用WAL
PRAGMA journal_mode = WAL;
-- WAL模式特点:
-- 1. 读写不冲突
-- 2. 更好的并发性能
-- 3. 支持多个读事务
-- 4. 写事务不阻塞读事务
-- 检查WAL状态
PRAGMA journal_mode;
七、并发控制 #
7.1 busy_timeout #
sql
-- 设置等待超时
-- 当遇到锁时,等待指定毫秒
PRAGMA busy_timeout = 5000; -- 等待5秒
-- 在应用程序中设置
-- Python: conn.execute("PRAGMA busy_timeout = 5000")
7.2 处理锁冲突 #
sql
-- 锁冲突错误
-- Error: database is locked
-- 解决方案:
-- 1. 增加busy_timeout
-- 2. 使用WAL模式
-- 3. 缩短事务时间
-- 4. 重试逻辑
-- Python示例
-- import sqlite3
-- import time
--
-- def execute_with_retry(conn, sql, max_retries=5):
-- for i in range(max_retries):
-- try:
-- return conn.execute(sql)
-- except sqlite3.OperationalError as e:
-- if 'locked' in str(e) and i < max_retries - 1:
-- time.sleep(0.1)
-- continue
-- raise
八、事务最佳实践 #
8.1 短事务 #
sql
-- 推荐:短事务
BEGIN;
INSERT INTO users (name) VALUES ('Test');
COMMIT;
-- 不推荐:长事务
BEGIN;
-- 大量操作...
-- 可能阻塞其他连接
COMMIT;
8.2 批量操作 #
sql
-- 批量操作使用事务
-- 不推荐
INSERT INTO users (name) VALUES ('User1');
INSERT INTO users (name) VALUES ('User2');
INSERT INTO users (name) VALUES ('User3');
-- 每条语句都是一个事务
-- 推荐
BEGIN;
INSERT INTO users (name) VALUES ('User1');
INSERT INTO users (name) VALUES ('User2');
INSERT INTO users (name) VALUES ('User3');
COMMIT;
-- 一个事务包含所有操作
8.3 错误处理 #
sql
-- 使用事务处理错误
-- Python示例
-- try:
-- conn.execute("BEGIN")
-- conn.execute("INSERT INTO users (name) VALUES (?)", ('John',))
-- conn.execute("INSERT INTO orders (user_id) VALUES (?)", (user_id,))
-- conn.commit()
-- except Exception as e:
-- conn.rollback()
-- raise
九、事务示例 #
9.1 银行转账 #
sql
-- 银行转账事务
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
user_name TEXT,
balance REAL
);
INSERT INTO accounts (user_name, balance) VALUES ('Alice', 1000);
INSERT INTO accounts (user_name, balance) VALUES ('Bob', 500);
-- 转账事务
BEGIN;
-- 检查余额
SELECT balance FROM accounts WHERE user_name = 'Alice';
-- 假设余额足够
-- 扣款
UPDATE accounts SET balance = balance - 100 WHERE user_name = 'Alice';
-- 入账
UPDATE accounts SET balance = balance + 100 WHERE user_name = 'Bob';
COMMIT;
9.2 订单处理 #
sql
-- 订单处理事务
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
total REAL,
status TEXT
);
CREATE TABLE inventory (
id INTEGER PRIMARY KEY,
product_name TEXT,
quantity INTEGER
);
INSERT INTO inventory (product_name, quantity) VALUES ('Product A', 100);
-- 订单事务
BEGIN;
-- 创建订单
INSERT INTO orders (user_id, total, status) VALUES (1, 50, 'pending');
-- 检查库存
SELECT quantity FROM inventory WHERE product_name = 'Product A';
-- 假设库存足够
-- 减少库存
UPDATE inventory SET quantity = quantity - 1 WHERE product_name = 'Product A';
-- 更新订单状态
UPDATE orders SET status = 'completed' WHERE id = last_insert_rowid();
COMMIT;
十、总结 #
事务操作 #
| 操作 | 语法 |
|---|---|
| 开始事务 | BEGIN [DEFERRED/IMMEDIATE/EXCLUSIVE] |
| 提交事务 | COMMIT |
| 回滚事务 | ROLLBACK |
| 创建保存点 | SAVEPOINT name |
| 回滚到保存点 | ROLLBACK TO SAVEPOINT name |
| 释放保存点 | RELEASE SAVEPOINT name |
最佳实践 #
- 使用事务包装相关操作
- 保持事务简短
- 使用WAL模式提高并发
- 设置合理的busy_timeout
- 正确处理事务错误
下一步,让我们学习数据库管理!
最后更新:2026-03-27