查看mysql隔离级别:
select @@tx_isolation;
show variables like '%tx_isolation%';
事务的四种隔离级别
set session transaction isolation level 隔离级别
1. read uncommitted : 读取尚未提交的数据:哪个问题都不能解决 2. read committed:读取已经提交的数据 :可以解决脏读 ---- oracle默认 会出现不可重复读,幻读 3. repeatable read:重读读取:可以解决脏读和不可重复读 ---mysql默认的,无法解决幻读 4. serializable:串行化:可以解决脏读、不可重复读和幻读---相当于锁表
serializable隔离级别下,所有select语句都会被隐式的转化为select …lock in share mode.这可能导致,如果有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住。
show variables like '%iso%'
版本控制很强,在设置set global transaction isolation level read committed;
时无法更改当前会话,可以在修改全局变量后修改会话set session transaction isolation level read committed;
类似重新加载变量
验证隔离级别操作步骤
开始验证之前,需要知道,MySQL默认开启autocommit,默认隔离级别为repeatable read
,MySQL事务的流程为begin ...end
。
在事务执行过程中,采用MVCC解决不可重复读问题。事务在默认隔离级别下,多版本控制数据库DML操作。
在模拟实验时需设置autocommit=off
,方便模拟
顺序 | 事务1 | 事务2 |
---|---|---|
1 | begin; | |
2 | begin; | |
3 | select * from sakila2.actor1 where actor_id=2; | |
4 | select * from sakila2.actor1 where actor_id=2; | |
5 | update sakila2.actor1 set first_name=‘kdd1’ where actor_id=2; | |
6 | commit; | |
7 | select * from sakila2.actor1 where actor_id=2; | |
8 | select * from sakila2.actor1 where actor_id=2; | |
9 | update sakila2.actor1 set first_name=‘kdd1’ where actor_id=2; | |
10 | commit; | |
11 | select * from sakila2.actor1 where actor_id=2; | |
12 | select * from sakila2.actor1 where actor_id=2; | |
13 | end; | |
14 | end; |
乐观锁和悲观锁
当我们说乐观锁和悲观锁时,它们的概念和事务锁(共享锁、排它锁)是完全不同的。
乐观锁和悲观锁是针对应用和数据库之间的一种取数和锁定策略。而事务锁是数据库为了解决数据库一致性问题出现的解决方案。这一点很重要。
所谓乐观锁,就是利用版本号比较机制,只是在读数据的时候,将读到的数据的版本号一起读出来,当对数据的操作结束后,准备写数据的时候,再进行一次数据版本号的比较,若版本号没有变化,即认为数据是一致的,没有更改,可以直接写入,若版本号有变化,则认为数据被更新,不能写入,防止脏写。版本号一般通过加字段的方式来实现,可以是自增标识,也可以是时间戳。
说明:以上为操作执行过程简要描述
说明:如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。
悲观锁是以悲观的态度面对高并发,此时高并发如果采用乐观锁会经常导致修改出现等待的情况。
在应用设计和存储过程开发时,应以最小代价方式选择乐观锁和悲观锁。一般b/s环境下,推荐使用乐观锁 。
高并发多修改,为什么使用悲观锁?
从下例中可以看出假设只是进行一次修改。
乐观锁的操作除了case1其余均返回错误。此时开销为5次查询,1次加锁,1次修改。悲观锁只有case1可以执行,其余均处于等待状态。此时开销为,1次查询,1次加锁,1次更新。所以使用悲观锁开销更小。
乐观锁
case 1 | case 2 | case 3 | case 4 | case 5 |
---|---|---|---|---|
update table set | update table set | update table set | update table set | update table set |
success | failure | failure | failure | failure |
返回信息 | 下一步操作 | 下一步操作 | 下一步操作 | 下一步操作 |
悲观锁
case 1 | case 2 | case 3 | case 4 | case 5 |
---|---|---|---|---|
update table set | 等待操作 | 等待操作 | 等待操作 | 等待操作 |
success | failure | failure | failure | failure |
返回信息 | 获取锁 | 获取锁 | 获取锁 | 获取锁 |