遇到mysql数据库事务隔离级别相关的小坑

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38132420/article/details/82971018

几乎所有软件工程师都知道,mysql有4种事务隔离级别,但是实际开发过程中可能有时候忽略这个小细节,有时候可能是本来就没有考虑过,有时候也可能是其他的原因,比如我这次踩到的小坑。

事情还原:
1、需求一:是新建一个商户,但是客户要求在创建商户的时候要默认给他们开一个管理员账户。其实很简单,就是新建一个商户,然后再新建一个账户,账户表中有一个字段关联商户。但是一看数据库隔离级别,是Read Committed(读取提交内容)。当时想着,算了,应该是其他项目需求需要用到这样的隔离级别,就先建立商户,然后再新建账户。当然,这就免不了各种错误处理。
2、需求二:每个用户会有一个默认收货地址,如果新增或者更新一个收货地址,且设置为默认的,那么需要将其他收货地址设置为非默认收货地址。受到需求一的影响。没看数据库隔离级别,就直接按照Read Committed(读取提交内容)这种隔离级别的方式开发,先插入(或者更新),如果是默认地址,将所有查出该用户所有的收货地址,将默认地址修改为非默认的地址。

结果:
如果需求一和需求二是在同一个数据库中的时候,其实是没问题的。因为事务隔离级别一致。但是刚好运维那边给开发迁移数据库的过程中,由于各种原因,事务隔离级别从Read Committed(读取提交内容)修改为Repeatable Read(可重读),这就会导致需求二中新插入或者更新的时候,会把先插入或者更新的记录被读取到,然后修改了。

教训:
1、特定的项目对于的数据库,最好约定好用同一种事务隔离级别。(这次采坑有个原因是同一个数据库,有多个项目一起用)
2、如果1条件不满足,最好在使用事务前设置会话对应的事务隔离级别

设置会话隔离级别
查看InnoDB存储引擎 系统级的隔离级别 和 会话级的隔离级别:

mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

设置innodb的事务级别方法是:set 作用域 transaction isolation level 事务隔离级别,例如~

SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

mysql> set global transaction isolation level read committed; //全局的

mysql> set session transaction isolation level read committed; //当前会话

基础知识
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
Read Uncommitted(读取未提交内容)

   在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)

   这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)

   这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

猜你喜欢

转载自blog.csdn.net/m0_38132420/article/details/82971018