INSERT INTO activity_logs (user_id, activity) VALUES ((SELECT user_id FROM users WHERE username = 'user_to_log'), 'Performed action X');
复制代码
2.4 事务控制语言(TCL)
开始事务
-- 开始一个简单事务
BEGIN TRANSACTION;
复制代码
提交事务
-- 提交一个简单事务
COMMIT;
复制代码
回滚事务
-- 回滚一个简单事务
ROLLBACK;
复制代码
保存点和回滚到保存点
-- 使用保存点
BEGIN TRANSACTION;
-- 插入一些数据
INSERT INTO users (username, password, email) VALUES ('test_user1', 'password1', 'test1@example.com');
-- 创建保存点
SAVEPOINT savepoint1;
-- 插入更多数据
INSERT INTO users (username, password, email) VALUES ('test_user2', 'password2', 'test2@example.com');
-- 回滚到保存点
ROLLBACK TO savepoint1;
-- 提交事务
COMMIT;
复制代码
嵌套事务(通过保存点模仿)
SQLite不支持真正的嵌套事务,但可以通过保存点模仿:
BEGIN TRANSACTION;
-- 插入数据
INSERT INTO users (username, password, email) VALUES ('nested_user1', 'password', 'nested1@example.com');
-- 第一个保存点
SAVEPOINT savepoint1;
-- 插入数据
INSERT INTO users (username, password, email) VALUES ('nested_user2', 'password', 'nested2@example.com');
-- 第二个保存点
SAVEPOINT savepoint2;
-- 插入数据
INSERT INTO users (username, password, email) VALUES ('nested_user3', 'password', 'nested3@example.com');
-- 回滚到第二个保存点
ROLLBACK TO savepoint2;
-- 提交事务
COMMIT;
复制代码
检查事务的同等性和完整性
通过事务确保同等性和完整性:
BEGIN TRANSACTION;
-- 插入用户和订单
INSERT INTO users (username, password, email) VALUES ('transaction_user', 'password', 'trans@example.com');
INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE username = 'transaction_user'), 500.00);
-- 检查插入是否成功
SELECT * FROM users WHERE username = 'transaction_user';
SELECT * FROM orders WHERE user_id = (SELECT id FROM users WHERE username = 'transaction_user');
-- 如果以上操作成功,则提交事务
COMMIT;
-- 如果操作失败,则回滚事务
ROLLBACK;
复制代码
事务控制中的非常处理
模仿在事务过程中出现非常,并进行回滚:
BEGIN TRANSACTION;
-- 插入数据
INSERT INTO users (username, password, email) VALUES ('exception_user', 'password', 'exception@example.com');
-- 模拟异常(尝试插入重复的唯一键)
INSERT INTO users (username, password, email) VALUES ('exception_user', 'password', 'exception@example.com');
-- 如果插入成功,则提交事务
COMMIT;
-- 如果插入失败,则回滚事务
ROLLBACK;
复制代码
高级事务管理
模仿复杂的事务管理,包罗多表操作:
BEGIN TRANSACTION;
-- 插入用户
INSERT INTO users (username, password, email) VALUES ('complex_user', 'password', 'complex@example.com');
-- 创建保存点
SAVEPOINT savepoint1;
-- 插入订单
INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE username = 'complex_user'), 1000.00);
-- 创建第二个保存点
SAVEPOINT savepoint2;
-- 插入订单项目
INSERT INTO order_items (order_id, product_id, quantity, price)
VALUES ((SELECT id FROM orders WHERE user_id = (SELECT id FROM users WHERE username = 'complex_user')), 1, 2, 500.00);
-- 回滚到第一个保存点
ROLLBACK TO savepoint1;
-- 提交事务
COMMIT;
复制代码
利用事务实现原子性操作
在多个操作组成的逻辑单元中利用事务,保证操作的原子性:
BEGIN TRANSACTION;
-- 查询用户信息
SELECT * FROM users WHERE username = 'atomic_user';
-- 插入订单
INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE username = 'atomic_user'), 200.00);
-- 更新用户信息
UPDATE users SET email = 'atomic@example.com' WHERE username = 'atomic_user';
-- 提交事务
COMMIT;
复制代码
回滚到指定保存点
在事务过程中,回滚到之前创建的指定保存点,撤销部分操作:
BEGIN TRANSACTION;
-- 插入用户信息
INSERT INTO users (username, password, email) VALUES ('rollback_user', 'password', 'rollback@example.com');
-- 创建保存点
SAVEPOINT savepoint1;
-- 插入订单
INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE username = 'rollback_user'), 300.00);
-- 插入订单项目
INSERT INTO order_items (order_id, product_id, quantity, price) VALUES ((SELECT id FROM orders WHERE user_id = (SELECT id FROM users WHERE username = 'rollback_user')), 1, 2, 150.00);
-- 回滚到保存点
ROLLBACK TO savepoint1;
-- 提交事务
COMMIT;
复制代码
多次保存点和回滚
在一个事务中创建多个保存点,并在需要时回滚到差异的保存点:
BEGIN TRANSACTION;
-- 插入用户信息
INSERT INTO users (username, password, email) VALUES ('multi_savepoint_user', 'password', 'multi_savepoint@example.com');
-- 创建保存点1
SAVEPOINT savepoint1;
-- 插入订单
INSERT INTO orders (user_id, total) VALUES ((SELECT id FROM users WHERE username = 'multi_savepoint_user'), 400.00);
-- 创建保存点2
SAVEPOINT savepoint2;
-- 插入订单项目
INSERT INTO order_items (order_id, product_id, quantity, price) VALUES ((SELECT id FROM orders WHERE user_id = (SELECT id FROM users WHERE username = 'multi_savepoint_user')), 1, 2, 200.00);
-- 回滚到保存点1
ROLLBACK TO savepoint1;
-- 提交事务
COMMIT;
复制代码
模仿事务超时和主动回滚
模仿长时间执行的事务,在指定时间后主动回滚:
BEGIN TRANSACTION;
-- 设置事务超时时间为10秒
PRAGMA busy_timeout = 10000;
-- 插入大量数据(模拟长时间执行)
INSERT INTO big_table (data) SELECT randomblob(1000000) FROM generate_series(1, 10000);
-- 提交事务
COMMIT;
复制代码
执行事务中的查询
在事务中执行查询操作,保证数据的同等性和可靠性:
BEGIN TRANSACTION;
-- 查询用户信息
SELECT * FROM users WHERE username = 'transaction_user';
-- 查询订单信息
SELECT * FROM orders WHERE user_id = (SELECT id FROM users WHERE username = 'transaction_user');
-- 提交事务
COMMIT;
复制代码
事务的嵌套和非常处理
模仿在事务内部发生非常时的回滚操作,包罗事务的嵌套:
BEGIN TRANSACTION;
-- 插入用户信息
INSERT INTO users (username, password, email) VALUES ('nested_transaction_user', 'password', 'nested@example.com');
-- 创建保存点
SAVEPOINT savepoint1;
-- 开始内部事务
BEGIN TRANSACTION;
-- 尝试插入重复的数据,模拟异常
INSERT INTO users (username, password, email) VALUES ('nested_transaction_user', 'password', 'nested@example.com');
iif(X,Y,Z):如果 X 为真,则返回值 Y,否则返回值 Z。iif(X,Y,Z) 函数在逻辑上等效于并生成与 CASE 表达式 “CASE WHEN X THEN Y ELSE Z END” 相同的字节码。
instr(X,Y):在字符串 X 中查找字符串 Y 的第一个出现,并返回先前字符的数量加 1,如果 Y 在 X 中没有找到,则返回 0。或者,如果 X 和 Y 都是 BLOB,则 instr(X,Y) 返回 Y 第一次出现之前的字节数加 1,如果 Y 在 X 中没有出现,则返回 0。如果 instr(X,Y) 的两个参数 X 和 Y 都是非 NULL,而且不是 BLOB,则都将解释为字符串。如果 instr(X,Y) 中的 X 或 Y 为空,则结果为 NULL。
like(X,Y)、like(X,Y,Z):用于实现 “Y LIKE X [ESCAPE Z]” 表达式。如果存在可选的 ESCAPE 子句,则利用 like() 函数调用三个参数。否则,仅利用两个参数调用它。请留意,相对于中缀 LIKE 运算符,like() 函数中的 X 和 Y 参数是颠倒的。X 是模式,Y 是要匹配该模式的字符串。因此,以下表达式是等价的:
name LIKE '%neon%'
like('%neon%',name)
复制代码
如果利用 sqlite3_create_function() 接口覆盖 like() 函数以更改 LIKE 运算符的操作,则重写 like() 函数时,紧张的是同时重写两个参数版本的 like() 函数。否则,根据是否指定了 ESCAPE 子句,可能会调用差异的代码来实现 LIKE 运算符。
likelihood(X,Y):likelihood(X,Y) 函数返回参数 X。likelihood(X,Y) 中的值 Y 必须是介于 0.0 和 1.0 之间的浮点常量。likelihood(X) 函数是一个无操作函数,代码生成器会优化它,以便在运行时(即在调用 sqlite3_step() 时)不斲丧 CPU 循环。likelihood(X,Y) 函数的目的是向查询规划器提供提示,即参数 X 是一个布尔值,其约莫有 Y 的概率为真。unlikely(X) 函数是 likelihood(X,0.0625) 的简写形式。likely(X) 函数是 likelihood(X,0.9375) 的简写形式。
load_extension(X):load_extension(X,Y) 函数从名为 X 的共享库文件中利用入口点 Y 加载 SQLite 扩展。load_extension() 的结果始终是 NULL。如果省略了 Y,则利用默认的入口点名称。如果扩展加载或初始化失败,则 load_extension() 函数会引发非常。
substr(X,Y,Z) / substring(X,Y,Z):substr(X,Y,Z) 函数返回输入字符串 X 的子字符串,从第 Y 个字符开始,长度为 Z 个字符。如果省略了 Z,则 substr(X,Y) 返回从第 Y 个字符开始直到字符串 X 的末端的所有字符。X 中最左边的字符为 1。如果 Y 为负数,则子字符串的第一个字符从右边计数而不是左边。如果 Z 为负数,则返回 Y 之前的 abs(Z) 个字符。如果 X 是字符串,则字符索引指的是实际的 UTF-8 字符。如果 X 是 BLOB,则索引指的是字节。
“substring()” 是从 SQLite 版本 3.34 开始的 “substr()” 的别名。
trim(X,Y):trim(X,Y) 函数返回一个字符串,该字符串由从 X 的两头删除在 Y 中出现的任何字符组成。如果省略了 Y 参数,则 trim(X) 从 X 的两头删除空格。
typeof(X):typeof(X) 函数返回一个字符串,指示表达式 X 的数据类型:“null”、“integer”、“real”、“text” 或 “blob”。
unhex(X):unhex(X,Y) 函数返回十六进制字符串 X 的解码的 BLOB 值。如果 X 包含任何不是十六进制数字且不在 Y 中的字符,则 unhex(X,Y) 返回 NULL。如果省略了 Y,则理解为空字符串,因此 X 必须是纯十六进制字符串。X 中的所有十六进制数字必须成对出现,每对数字的两个数字立即相邻,否则 unhex(X,Y) 返回 NULL。如果参数 X 或 Y 中的任一参数为 NULL,则 unhex(X,Y) 返回 NULL。X 输入可能包含任意混合大小写的十六进制数字。Y 中的十六进制数字不影响 X 的转换。在 unhex(X,Y) 中忽略 Y 中的非十六进制数字。
查看文档会更方便,因为它会提供更详细的信息和示例。