二、MySQL调优之事务:高并发场景下的数据库事务调优

常用的数据库引擎为InnoDB和MyISAM,MyISAM不支持事务处理,所以Mysql事务基于InnoDB引擎。
数据库事务具有以下四个基本属性:原子性(Atomicity)、一致性(Consistent)、隔离性(Isolation)以及持久性(Durable)。正是这些特性,才保证了数据库事务的安全性。

一.并发事务带来的问题

1、数据丢失

mysql 新增并发问题 mysql 并发更新性能_隔离级别


据丢失可以基于数据库中的悲观锁来避免发生,即在查询时通过在事务中使用 select xx for update 语句来实现一个排他锁,保证在该事务结束之前其他事务无法更新该数据。

也可以基于乐观锁来避免,即将某一字段作为版本号,如果更新时的版本号跟之前的版本一致,则更新,否则更新失败。

2、脏读(读未提交,B事务在A事务提交之前就读到了修改后的数据,但是A事务发生了回滚,B事务读取到的是错误数据)

mysql 新增并发问题 mysql 并发更新性能_mysql 新增并发问题_02

3、不可重复读

mysql 新增并发问题 mysql 并发更新性能_隔离级别_03

4、幻读

mysql 新增并发问题 mysql 并发更新性能_mysql_04

二.事务隔离解决并发问题

隔离级别

脏读

不可重复读

幻读

读未提交(read uncommitted)




读已提交 (read committed)




可重复读 (repeatable read)




串行化(serializable)




1、读未提交(Read Uncommitted)

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到,是最不靠谱的。

2、读已提交(Read Committed,Oracle默认隔离级别)

事务成功提交后才可以被查询到。

3、可重复读(Repeatable Read,MYSQL默认隔离级别)

事务B在事务A提交之前值可以读取,不可以修改。

在事务 A 读取数据时增加了共享锁,事务结束,才释放锁,事务 B 读取修改数据时增加了行级排他锁,直到事务结束才释放锁。也就是说,事务 A 在没有结束事务时,事务 B 只能读取数据,不能修改。当事务 A 结束事务,事务 B 才能修改。这种隔离级别,可以避免脏读、不可重复读,但依然存在幻读的问题。

4、串行化(Serializable)

串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行,但是种方式对数据库性能的影响极高,一般不用。

三.锁具体实现算法

1、结合业务场景,使用低级别事务隔离(使用读已提交)

在高并发业务中,为了保证业务数据的一致性,操作数据库时往往会使用到不同级别的事务隔离。隔离级别越高,并发性能就越低。

2、避免行锁升级表锁

在 InnoDB 中,行锁是通过索引实现的,如果不通过索引条件检索数据,行锁将会升级到表锁。我们知道,表锁是会严重影响到整张表的操作性能的,所以我们应该避免他。

3、控制事务的大小,减少锁定的资源量和锁定时间长度(尽量的减少锁的持有有时间)

mysql 新增并发问题 mysql 并发更新性能_数据库_05


执行顺序1比较合适,因为扣除库存会持有锁,而新建订单并不会持有锁,将需要持有锁的操作放在最后,尽量减小锁的持有时间。