您的位置:首页 > 数据库 > MySQL

关于Mysql的默认事务隔离级别 read repeatable

2018-05-08 15:27 666 查看
查询mysql的事务隔离级别 SELECT @@tx_isolation ;

一、数据库事务的隔离级别有4种:

由低到高分别为:Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。下面通过事例一一阐述它们的概念与联系。

其中,mysql默认为 repeatable Read , 一个事务开始后,

1、如果针对一个字段的值 无论查询多少次,结果都是相同的,即使这个值已经被其它事务修改过。

2、如果是做统计,统计到的数据行数结果不会变,即使其它事务已经插入了新记录。

所以 Repeatable Read 是有害的 ,如何避免呢?

顺便说一下相关的几个概念:

1. 脏读 :其它事务还没提交就被另当前事务读取到了,理解:脏就是不想要的,不是真正需要的。坏事。

2. 不可重复读 :当前事务两次读到的数据不一致,因为其它事务也在修改并提交,我认为这不是坏事,因为数据是真实的。repeatable read级别的隔离是不存在的,read commited 中存在,看上去这是好事啊。

3. 幻读 : 简单理解是当前事务两次查询发现数据不一致,结果是由于其它事务插入了数据(已经提交)导致的。 幻读可以理解为海市蜃楼(光的折射),感觉像幻像实际是都是真实的信息。 好事。

二、如何避免Repeatable Read 导致的问题:

1、关于修改某字段的值时,一定要使用乐观锁或者悲观锁。

例如更新账户金额: update order_info o set o.money=money-10

而不应该先查询money 计算完成后再进行更新

money = money -10 ; --- 这里money可能早被其它事务改了

update order_info o set o.money= :money

三、验证事务Mysql的事务隔离级别

建好表,打开两个mysql命令行窗口,插入一条记录 age=1 ,然后通过两个并发事务对age分别加1,预期接结果为 3

1)两个窗口分别开始事务

start TRANSACTION ;

2)窗口一更新表

update user_info set age = age+1 where id=1;

3)窗口二更新 表

update user_info set age = age+1 where id=1 ;

此时发现窗口二卡住了,实际上如果sql中没有在where条件中使用索引的话,不论更新哪个字段都会被卡住。为什么?

因为在采用INNODB的MySQL中,更新操作默认会加行级锁.所以窗口二这里会卡住。

行级锁是基于索引的。如果没有使用索引则会锁表,如果操作用到了主键索引会先在主键索引上加锁,然后在其他索引上加锁,否则加锁顺序相反。在并发度高的应用中,批量更新一定要带上记录的主键,优先获取主键上的锁,这样可以减少死锁的发生。

4)窗口一 提交事务

commit;

此时数据库中的age值为2

5)窗口二 恢复后,

查询age:

select age from user_info 发现 age结果还是为 1 (这是因为repeatable read 隔离级别导致)

再次执行 更新

update user_info set age = age+1;

然后进行查询

select age from user_info 发现 ,查询结果是正确:3 而不是错误的 2

6) 窗口二 commit ;

打开数据库查看,结果为 3

参看文章:http://ju.outofmemory.cn/entry/199937
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: