参考链接
https://juejin.im/post/5b90cbf4e51d450e84776d27
事务
事务是控制并发的基本单位。
事务是一个操作序列,这些操作要么都执行,要么都不执行,是一个不可分割的工作单位。
查询 Mysql 的事务隔离级别
select @@tx_isolation;
查询当前的事务
查询当前正在进行的事务。
select * from information_schema.INNODB_TRX;
开启事务
// method 1
start transaction;
// method 2
begin
回滚
rollback;
提交事务
commit;
创建示例:
create table bank (
id int(10) unsigned not null AUTO_INCREMENT,
name varchar(40) not null,
blance decimal(10, 2) null,
primary key (`id`)
);
并发事务带来的问题
第一类丢失更新
第一类丢失更新,事务 A 撤销时,会把已提交的事务 B 的记录覆盖掉。
这是完全没有事务隔离造成的。
第二类丢失更新
事务 A 提交时,把已经提交的事务 B 的更新数据覆盖掉了。
- 第一类丢失更新和第二类丢失更新的区别是,对事务的影响是事务 A 提交还是撤销造成的。
- 事务 A 撤销对数据造成影响是完全没有事务隔离导致的,这种情况一般不会出现;
事务 B 提交对数据造成影响,本质上是不可重复读的一个特例。
脏读
验证这个例子时,不能使用 DBeaver 等第三方工具,因为这个工具本身也会提供事务选型,要到命令行里面去验证。
一个事务读到另外一个事务未提交更新的数据。
未提交更新的数据,事务最终未提交数据,比如回滚了数据。
事务 A 查询到账户余额为 500元后,事务 B 进行了回滚了,事务A查询到的账户余额 500 元变成了脏数据。
- 事务 A 接下来在脏数据的基础上继续改动,最终的结果也就是错误的。
现在为止:所有的数据库都避免脏读。在默认的隔离级别下(REPEATABLE-READ ), 事务 A 在 T5 读到的数据是 1000 。
不可重复读
读到已经提交更新的数据,一个事务内两次相同的查询的结果不一样。
幻读
- 不可重复读是读到更新的数据,幻读是读到新插入的数据或删除的数据。
正因如此,不可重复读是一个事务范围内两次相同的查询返回了不同的查询结果。
幻读是事务 A 查询到了与搜索条件相匹配的若干行,事务 B 以插入或删除的方式修改了事务 A 的结果集再提交。
// 事务 B
start transaction;
// 事务 A
start transaction;
select sum(blance) from bank where name='fufu';
insert into bank (name, blance) values ('fufu', 2000000);
commit;
select sum(blance) from bank where name='fufu';
事务的隔离级别
串行化 Serializable
当两个事务同时操作数据库中相同数据时,如果第一个事务已经在访问该数据,第二个事务只能停下来等待,必须等到第一个事务结束后才能恢复运行。因此这两个事务实际上是串行化方式运行。并发事务带来的问题都没有了。
可重复读 Repeatable read
可重复读的隔离级别,有幻读问题(即有新数据插入时还会看到),但是看不到其他事务对已有数据的更新。就是在一个事务内,两次相同的查询的结果都是相同的。
读已提交的数据 Read Commited
即幻读和不可重复读的问题都存在,在一个事务期间,即会看到其他事务已经更新的记录,也会看到新插入的数据。
读未提交的数据 Read Uncommited
当数据库系统使用READ UNCOMMITTED隔离级别时,一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且还能看到其他事务没有提交的对已有记录的更新。
隔离级别与性能
隔离级别与并发问题
| 隔离级别 | 第一类丢失更新 | 第二类丢失更新 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|---|---|
| SERIALIZABLE (串行化) | 避免 | 避免 | 避免 | 避免 | 避免 |
| REPEATABLE READ(可重复读) | 避免 | 避免 | 避免 | 避免 | 允许 |
| READ COMMITTED (读已提交) | 避免 | 允许 | 避免 | 允许 | 允许 |
| READ UNCOMMITTED(读未提交) | 避免 | 允许 | 允许 | 允许 | 允许 |
- 幻读的问题很难避免;
