1. 隐含的执行unlock tables
如果在锁表期间,用start transaction命令来开始一个新事务,会造成一个隐含的unlock tables 被执行,如下所示:
会话1 | 会话2 |
SELECT * FROM country WHERE country='德国'; 记录为空 | SELECT * FROM country WHERE country='德国'; 记录为空 |
-- 对country表进行加 写锁 LOCK TABLE country WRITE; | |
-- 查询 整个表读取被阻塞 SELECT * FROM country WHERE country='德国'; | |
-- 插入一条记录 INSERT INTO country(country, last_update) VALUES('德国',NOW()); 共 1 行受到影响 country_id country last_update 2 中国 2018-07-03 18:06:45 7 德国 2018-07-12 17:22:08 | 查询等待 |
-- 开始一个新事务 START TRANSACTION; | |
会话1开始一个新事务时,表锁被释放,可以查询: SELECT * FROM country; country_id country last_update 2 中国 2018-07-03 18:06:45 7 德国 2018-07-12 17:22:08 |
在同一个事务中,最好不要操作不同存储引擎的表, 因为只有commit 和rollback 只能对事务类型的表进行提交和回滚。通常 提交的事务记录会到二进制的日志中, 但如果一个事务中包含非事务类型的表,那么回滚操作也会被记录到二进制日志中,以确保非事务类型表的更新可以被复制到从slave数据库中。
2. savepoint
在事务中可以通过定义 savepoint,指定回滚事务的一个部分,但是不能提交提交事务的一个部分, 对于复杂的应用,可以定义多个不同的savepoint 来适应不同的条件,回滚不同的savepoint。如果定义了相同名字的savepoint,则后面定义的savepoint会覆盖之前的定义。对于不再需要使用的savepoint,可以通过release savepoint 来删除savepoint。
下面举例回滚事务的一个部分,通过定义savepoint来指定需要回滚的事务的位置。
会话1 | 会话2 |
SELECT * FROM country WHERE country='德国'; 结果为空 | SELECT * FROM country WHERE country='德国'; 结果为空 |
-- 启动一个事务 插入一条记录 START TRANSACTION ; INSERT INTO country(country, last_update) VALUES('德国',NOW()); | |
-- 可以查询到刚插入的记录 SELECT * FROM country WHERE country='德国'; country_id country last_update 12 德国 2018-07-12 18:17:12 | SELECT * FROM country WHERE country='德国'; 结果为空 |
-- 定义savepoint 名为testsavepoint SAVEPOINT savepoint_test; -- 继续插入一条记录, 此时事务还会提交 INSERT INTO country(country, last_update) VALUES('日本',NOW()); | |
SELECT * FROM country WHERE country='德国' or country='日本' 结果为空 | |
SELECT * FROM country WHERE country='德国' or country='日本' country_id country last_update 12 德国 2018-07-12 18:17:12 13 日本 2018-07-12 18:20:33 | |
-- 回滚刚才的定义 ROLLBACK TO SAVEPOINT savepoint_test; | |
SELECT * FROM country WHERE country='德国' OR country='日本' country_id country last_update 12 德国 2018-07-12 18:17:12 | SELECT * FROM country WHERE country='德国' or country='日本' 结果为空 |
-- 提交事务 COMMIT; | |
SELECT * FROM country WHERE country='德国' OR country='日本' country_id country last_update 12 德国 2018-07-12 18:17:12 | SELECT * FROM country country_id country last_update 2 中国 2018-07-03 18:06:45 12 德国 2018-07-12 18:17:12 |