今天大年初五迎财神,那么提到“财”,我们是否考虑过一个问题:转账会不会出现钱扣了对方也没收到钱的情况?首先财神不同意,另外按照现在的技术,基本也不会出现,因为目前一个转账操作基本在一个事务中。事务内的语句,要么全部执行成功,要么全部执行失败。也就是说,上面转账过程中,即使中间出现问题,也会回滚,取消扣钱操作。
那 MySQL 事务还有哪些特性呢?这一节内容就来聊聊。
开始一个事务
begin;
或者
start transaction;
提交事务:
commit;
回滚事务
rollback;
参数 autocommit 可以控制当前会话是否自动提交,如果值为 1,则表示自动提交,每次执行事务不需要我们执行 begin 或者 start transaction。
如果全局为自动提交,但是想要部分 SQL 禁用自动提交,则使用下面的方法:
start transaction;
update table1 set a=1 where id=1;
update table2 set a=2 where id=1;
commit;
一个运行良好的事务处理系统,必须具备 ACID 特性:
至于 MySQL 是如何来保证这些特性,我们在后面的文章详细介绍。
MySQL 有四种隔离级别:
如何选择合适的隔离级别:
执行下面 SQL,进行实验前准备:
use martin;
drop procedure if exists insert_t1;
delimiter ;;
create procedure insert_t1()
begin
drop table if exists t1;
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_c` (`a`)
) ENGINE=InnoDB CHARSET=utf8mb4;
insert into t1(a,b) values (1,1),(2,2);
end;;
delimiter ;
4.1 Read Committed 实验
执行初始化语句:
call insert_t1();
进行实验:
session1 | session2 |
---|---|
set session transaction_isolation='READ-COMMITTED'; | set session transaction_isolation='READ-COMMITTED'; |
begin; | begin; |
select * from t1 where a=1; | |
insert into t1(a,b) values (1,3); | |
select * from t1 where a=1; | |
commit; | |
select * from t1 where a=1; | |
commit; |
session2 写入了新数据未提交的情况下,session1 无法查看到新记录,等到 session2 提交之后,session1 才能看到 session2 写入的数据。出现了一个事务中的两次执行同样的查询,得到不一样的结果,也就是幻读。
4.2 Repeatable Read 实验
执行初始化语句:
call insert_t1();
进行实验:
session1 | session2 |
---|---|
set session transaction_isolation='REPEATABLE-READ'; | set session transaction_isolation='REPEATABLE-READ'; |
begin; | begin; |
select * from t1 where a=1; | |
insert into t1(a,b) values (1,3); | |
select * from t1 where a=1; | |
commit; | |
select * from t1 where a=1; | |
commit; | |
select * from t1 where a=1; |
session2 写入了新数据未提交的情况下,session1 无法查看到新记录,等到 session2 提交但是 session1 还未提交时,session1 还是不能看到新记录,没有出现 RC 隔离级别实验的幻读现象。需要等 session1 事务提交之后,才能查看到 session2 写入的新数据。
今天的内容就到这里,《MySQL 基础知识笔记》系列文章持续更新中