查询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