MySQL深入理解MySQL锁和事务隔离级别
Posted boluo1230
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL深入理解MySQL锁和事务隔离级别相关的知识,希望对你有一定的参考价值。
先看个小案例:
- 话不多说,上案例,先创建一个表
mysql> CREATE TABLE IF NOT EXISTS `account`( `id` INT UNSIGNED AUTO_INCREMENT, `name` VARCHAR(60), `balance` INT(11) DEFAULT NULL, PRIMARY KEY (id))ENGINE=innodb charset=utf8mb4;
- 插入几条数据
mysql> insert into account(name,balance) values(\'lilei\',450); Query OK, 1 row affected (0.00 sec) mysql> insert into account(name,balance) values(\'hanmei\',16000); Query OK, 1 row affected (0.00 sec) mysql> insert into account(name,balance) values(\'lucy\',2400); Query OK, 1 row affected (0.00 sec)
- 此时可以看到三条数据:
mysql> select * from account; +----+--------+---------+ | id | name | balance | +----+--------+---------+ | 1 | lilei | 450 | | 2 | hanmei | 16000 | | 3 | lucy | 2400 | +----+--------+---------+ 3 rows in set (0.00 sec)
- 我们开启两个命令行界面,然后实践一下
1》我们先在一个命令行(下面称为命令行A)中,执行一段事务操作,但是不提交
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update account set balance=3000 where id=3; Query OK, 1 row affected (0.07 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from account; +----+--------+---------+ | id | name | balance | +----+--------+---------+ | 1 | lilei | 450 | | 2 | hanmei | 16000 | | 3 | lucy | 3000 | +----+--------+---------+ 3 rows in set (0.00 sec)
2》然后在另一个命令行(下面称为命令行B)中,进行一次修改操作:
mysql> update account set balance=3500 where id =3;
3》可以看到在命令行B中,并不会看到修改结构,因为命令行A中的事务会默认加上一个行锁,只要事务不停,行锁就一直保留:
4》此时我们在命令行A中进行提交,在命令行B中会看到提交返回:
5》但是命令行A提交了事务后,因为A本想将ID为3的用户【balance】修改为3000,可此时查看结果后发现:
6》所以此时A对ID为3的用户的修改未达到理想值
- 此处引申一点,由于MySQL的默认隔离级别是行锁,如何验证它是行锁呢:
- 我们在A中修改【ID=3】的数据,然后在B中修改【ID=2】的数据,可以明显看到有结果返回,由此可以证明,锁仅仅是加在行上的
此时我们言归正传:
- 事务与ACID属性:
原子性(Atomicity)、一致性(Consistent)、隔离性(Isolation)、持久性(Durable)
- 并发事务处理带来的问题:
1》更新丢失:两个事务同事操作相同数据,后提交的事务会覆盖先提交的事务处理结果,通过乐观锁就可以解决。(即文章开篇介绍的案例) 2》脏读:事务A读取到了事务B已经修改,但尚未提交的数据,如果事务B回滚,A读取的数据无效,不符合一致性。 3》不可重读:事务A读取到了事务B已经提交的修改数据,不符合隔离性。 4》幻读:事务A读取到了事务B提交的新增数据,不符合隔离性。
- 事务隔离级别:
- 常看数据库事务隔离级别:
mysql> show variables like \'tx_isolation\'; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+
- 设置事务隔离级别:
mysql> set tx_isolation=\'REPEATABLE-READ\';(其他三种:READ-UNCOMMITTED,READ-COMMITTED,SERIALIZABLE)
- 此时我们分别聊聊剩下的案例,为了方便验证,我们先把隔离级别设置到最低级:
mysql> set tx_isolation =\'READ-UNCOMMITTED\';
1》脏读,不废话,直接上实例:
分析一下,上述指令,我们按顺序执行,可以看出因为事务B(右面)最后进行了回滚操作,但是事务A(左面)两次执行结果并不一样,造成了脏读情况。
2》不可重读,也不废话,线上案例:
分析来看,上述指令情况使得原子的一致性和隔离性均未实现,因为事务A还没有结束,所以两次所读数据应该一致,才可以保证事务实现一致性和隔离性。
3》幻读,先不墨迹,看案例就完了:
事务A一直处在一个事务内,但事务B缺新增了数据并提交了,而事务A两次查询结果不一致,从而该情况叫幻读。
- 数据库默认隔离级别是【可重复度】,但是并没有解决【幻读】情况,请问为什么不使用【可串行化】呢?
因为【可串行化】的性能非常低,如果一个商城,开了【可串行化】的级别后,下个订单却要一分钟,这种用户体验你会接受么^ - ^
以上是关于MySQL深入理解MySQL锁和事务隔离级别的主要内容,如果未能解决你的问题,请参考以下文章