来来来!我给你演示下高并发场景下的数据库事务调优( 二 )


  1. 避免行锁升级表锁
我们知道 , InnoDB中行锁是通过索引实现的 , 当不通过索引条件检索数据时 , 行锁就会升级成表锁 , 我们知道表锁会严重影响我们对整张表的操作 , 应该避免这种情况 。
  1. 控制事务的大小 , 减少锁定的资源和锁定的时间
下边这个SQL异常相比很多并发比较高的系统里都会遇见 , 比如抢购系统的日志中:
MySQLQueryInterruptedException: Query execution was interrupted复制代码由于抢购系统中 , 提交订单业务开启了事务 , 在并发环境中对一条记录进行更新操作的情况下 , 由于更新记录所在的事务还可能存在其他操作 , 导致一个事务比较长 , 当大量请求进入时 , 就可能导致一些请求同时进入事务中 , 由于锁的竞争是不公平的 , 当多个事务同时对一条记录进行更新时 , 极端情况下 , 一个更新操作进去排队系统后 , 可能会一直拿不到锁 , 最后因超市被系统中断 , 就会抛出上边这个异常 。
提交订单需要创建订单和扣减库存 , 两种不同顺序的执行方式 , 结果都一样 , 但是性能确实不一样的:
来来来!我给你演示下高并发场景下的数据库事务调优文章插图
这两种不同的执行方式 , 虽然这些操作都在一个事务中 , 但是锁的申请不在同一时间 , 锁只有当其他操作都执行完成才会释放锁 。 扣减库存是更新操作 , 属于行锁 , 如果先扣减库存会影响到其他操作该数据的事务 , 所以我们应该尽可能地避免长时间持有该锁 , 尽快的释放锁 。
因为创建订单和扣除库存不管先执行哪一步都不影响业务 , 所以我们可以先执行新增操作 , 把扣除库存放到最后 , 也就是使用执行顺序1, 来减少锁的持有时间 。
总结MySQL 的并发事务调优和 Java 的多线程编程调优非常类似 , 都是可以通过减小锁粒度和减少锁的持有时间进行调优 。 在 MySQL 的并发事务调优中 , 我们尽量在可以使用低事务隔离级别的业务场景中 , 避免使用高事务隔离级别 。
在功能业务开发时 , 我们往往会为了追求开发速度 , 习惯使用默认的参数设置来实现业务功能 。 例如 , 在 service 方法中 , 你可能习惯默认使用 transaction , 很少再手动变更事务隔离级别 。 但要知道 , transaction 默认是 RR 事务隔离级别 , 在某些业务场景下 , 可能并不合适 。 因此 , 我们还是要结合具体的业务场景 , 进行考虑 。
【来来来!我给你演示下高并发场景下的数据库事务调优】作者:故里同学呀链接:来源:掘金著作权归作者所有 。 商业转载请联系作者获得授权 , 非商业转载请注明出处 。