数据库锁处理并发
2018-04-20 本文已影响35人
hello_coke
前言:由于一些原因简书已经一年多没有更新,最近开始会重新维护起来,后续会分享一些自己沉淀的东西!
一、乐观锁
常用实现乐观锁方式:
1、表里面添加version字段(默认1),在更新的时候同时添加version校验,如:
update XXX set XXX,version=version + 1 where version = 原version(入参传入)
这个用法会用在前端配置防止并发以及重置,切记在更新的时候该version需要从前端带到后端,这种方式有些局限性,version字段没有实际的语义
2、表里面添加状态字段,来作为前置状态校验,比如订单表中支付成功需要将已创建待支付的订单更新为已支付
update XXX set status = 'PAID' where status = 'UNPAID'
这个用法使用很广如在订单中心或者一些中台业务系统
不常用的实现乐观锁方式:
3、实现方式跟第一点类似,因为我们表里面经常会有更新时间gmt_modified字段,该字段可以设置为TIMESTAMP(3)(精确到1ms)
这种的像更新订单表里面的某几个字段可能不好用第二种情况状态机来控制,用时间戳来作为乐观锁也是一种很好的方式
update XXX set attribute = XXX where gmt_modified = XXX
二、悲观锁
悲观锁不要轻易使用,能不用的就不要使用,因为悲观锁是独占锁,其余任务更新被锁住的数据会等待。使用方式:
select * from XXX where id=1 for update
有个点必须注意,因为默认情况下数据库更新操作都是自动提交的,所以在应用层使用悲观锁的时候应该放在事物中
有个典型的需要使用悲观锁的场景,比如一个主订单下面有2个子订单,当子订单都被取消的时候需要将主订单的状态推成取消。两个子订单同时在两个不同的请求调用中被取消,这个时候需要使用悲观锁锁住先锁主主订单防止并发,最终当两个子单都被取消的时候主订单状态被推成取消
三、数据库锁应用畅想
数据库锁是一种相对比较简单的防止并发的有效方案,在一些通过定时任务来调度的任务,当需要同时执行 n个定时任务的时候,为了处理并发这个时候采用乐观锁中第2条通过明确的状态机抢占到数据再去处理,这样就能做到同一个单据被重复捞取。如上就是一些比较基本的手段,掌握好就可以通过不同的场景交叉使用。