java设置mysql隔离级别_Mysql四种事务隔离级别

先了解一下事务的四大特性:ACID

原子性(Atomicity)

原子性就是不可拆分的特性,要么全部成功然后提交(commit),要么全部失败然后回滚(rollback)。MySQL通过Redo Log重做日志实现了原子性,在将执行SQL语句时,会先写入redo log buffer,再执行SQL语句,若SQL语句执行出错就会根据redo log buffer中的记录来执行回滚操作,由此拥有原子性。

一致性(Consistency)

一致性指事务将数据库从一种状态转变为下一种一致的状态。比如有一个字段name有唯一索引约束,那么在事务前后都不能有重复的name出现违反唯一索引约束,否则回滚。MySQL通过undo Log实现一致性,执行SQL语句时,会先写入undo log再写入 redo log buffer。undo是逻辑日志,会根据之前的SQL语句进行相应回滚,并且除了回滚,undo log还有一个作用是MVCC,当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可通过undo读取之前的行版本信息,实现非锁定读取。并且undo log也会产生redo log,因为undo log也需要持久性的保护。

隔离性(Isolation)

如果没有隔离性会发生如下问题:

1,数据丢失:A事务撤销时,把已经提交的B事务的更新数据覆盖了。

2,脏读:脏读主要是读取到了其他事务的数据,而其他事务随后发生回滚。MySQL通过三级封锁协议的第二级解决了脏读,在一级的基础上,要求读取数据 A 时必须加 S 锁,读取完马上释放 S 锁。

3,不可重复读:不可重复读是读取到数据后,随后其他事务对数据发生了修改,无法再次读取。MySQL通过三级封锁协议的第三级解决了不可重复读。在二级的基础上,要求读取数据 A 时必须加 S 锁,直到事务结束了才能释放 S 锁。

4,幻读:幻读是读取到数据后,随后其他事务对数据发生了新增,无法再次读取。在InnoDB引擎Repeatable Read的隔离级别下,MySQL通过Next-Key Lock以及MVCC解决了幻读,事务中分为当前读以及快照读。

快照读(snapshot read) ——通过MVCC来避免幻读

简单的select操作(不包括 select … lock in share mode, select … for update)

当前读(current read) ——通过Next-Key Lock 来避免幻读 Next-Key Lock即间隙锁(Gap Lock)+行锁 (Record Lock);

持久性(Durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。具体实现原理就是在事务commit之前会将,redo log buffer中的数据持久化到硬盘中的redo log file,这样在commit的时候,硬盘中已经有了我们修改或新增的数据,由此做到持久化。

Mysql的四大隔离级别

区别

Mysql默认隔离级别REPEATABLE-READ

63a61d24cc34729450105f9467aaa3da.png

演示四大隔离级别

建表语句

DROP TABLE IF EXISTS `user_account`;

CREATE TABLE `user_account` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`user_id` int(11) NOT NULL,

`balance` int(11) NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

当前环境和版本

de1c986057204b017a78e622a6aef6ba.png

读未提交read-uncommit

打开一个客户端A,并设置当前事务模式为read uncommitted(未提交读),查询表user_account的初始值:

a0a43168757e4d14b2ef47281109fdb1.png

在客户端A的事务提交之前,打开另一个客户端B,更新表user_account:

05b13ef450e32ab95c5e8bc9496083e7.png

此时在回到客户端A查询数据结果为:

39a2c3bceb940d9cf5183b616eb3c1ad.png

这时候客户端B事务还没有提交,然后客户端A就能查到数据客户端B更新的数据了。那么一旦客户端B执行(ROLLBACK)回滚了事务,那么此时就会导致客户端A的数据脏读。

提交已读(read-commit)

打开一个客户端A,并设置当前事务模式为read committed(读已提交),查询表user_account的所有记录:

35b1f26e4cd3e21487720a4735a041c9.png

在客户端A的事务提交之前,打开另一个客户端B,更新表user_account并提交;

9bfd0090d7d72f046edeeeea1b3a30d7.png

在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题

ac90092e33b5e2ef200035c2e71b2d3c.png

可重复读(repeatable-read)

打开一个客户端A,并设置当前事务模式为repeatable read,查询表user_account的所有记录

a41d4848176e887a34b9e81dbb32447e.png

在客户端A的事务提交之前,打开另一个客户端B,更新表user_account并提交

f2203a59287bd56b5e0d3827520cd193.png

在客户端A查询表user_account的所有记录,与客户端执行事务之前查询结果一致,没有出现不可重复读的问题

85564ec71b431cb9033c2b7991845e5d.png

在客户端B插入一条数据

e538ddeafcff7a3cfa581a24d9918014.png

在客户端A中还是没有数据

ad4509c8b554ad8e734cbec5ee486b31.png

串行化(serializable)

打开一个客户端A,并设置当前事务模式为serializable,查询表user_account的初始值:

8358dbed7903c12780ef543e9be215e6.png

打开一个客户端B,并设置当前事务模式为serializable,插入一条记录报错,表被锁了插入失败,mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到

补充:

1、事务隔离级别为读提交时,写数据只会锁住相应的行

2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

3、事务隔离级别为串行化时,读写数据都会锁住整张表

4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

5、MYSQL MVCC实现机制参考链接:

https://blog.csdn.net/whoamiyang/article/details/51901888

6、关于next-key 锁可以参考链接:

https://blog.csdn.net/bigtree_3721/article/details/73731377

参考:https://www.cnblogs.com/huanongying/p/7021555.html

关注回复福利,有惊喜哟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值