一个关于数据库级别的并发问题

J2EE 码拜 7年前 (2017-05-04) 1599次浏览
需求:流水表的订单号对于交易A是允许重复的,但是对于交易B是不允许重复的。程序需要部署负载均衡。
设计:
交易A可以直接插入数据库
交易B需要先根据订单号去数据库查询下有没有这条数据,没有才执行插入
问题:
假如B交易有并发请求的时候(订单号相同)查的时候是没有数据但是查询完之后另一个并发请求插入了数据,然后这个查询的也插入了数据,那就会造成B交易在数据库有重复订单号的情况。
图示:
一个关于数据库级别的并发问题
解决方案:问一下怎么解决这个问题。
解决方案

10

引用:

有人吗?求指导答呀

题主本人有个小小的建议,为什么不考虑把订单号设计成 兼容负载的呢?
你这一步假如是单节点没问题, 假如B交易有并发请求的时候(订单号相同)查的时候是没有数据但是查询完之后另一个并发请求插入了数据 可以考虑 在查的时候 加一把公共资源锁 ,为了保证 全部负载的服务可以及时获取到相关锁信息。

5

建议把订单号生产写成一个服务或单例  写生成单据号的方法为同步即加锁   这样保证获取的单据号是不重复的

5

用存储过程。 存储过程可以保证一次操作在一个事务中,并能保证操作的原子性。

5

引用:

用存储过程。 存储过程可以保证一次操作在一个事务中,并能保证操作的原子性。

把查询订单号和插入订单号这两个操作放在一个存储过程中,程序只需要调用这个存储过程即可。
各大关系性数据库均支持存储过程。

5

引用:
Quote: 引用:
Quote: 引用:

有人吗?求指导答呀

题主本人有个小小的建议,为什么不考虑把订单号设计成 兼容负载的呢?
你这一步假如是单节点没问题, 假如B交易有并发请求的时候(订单号相同)查的时候是没有数据但是查询完之后另一个并发请求插入了数据 可以考虑 在查的时候 加一把公共资源锁 ,为了保证 全部负载的服务可以及时获取到相关锁信息。

你说的加公共资源锁的具体实现是什么?能麻烦说下吗?之前有想过,在插入订单表之前先插入一张C表,然后C表设置一个唯一索引,只有C表插入成功的才接着插入订单表。这样似乎可以解决这个问题。然后想知道有没有更好的实现方案。

题主都已经知道是并发引起的数据重复,那你设计的C表也是会出现这个问题的。原因是你的操作都是SELECT –>  INSERT,
只要并发操作存在,这个动作就会引起数据重复
题主可以参考 redis 分布式锁,想简单的话可以利用自旋锁的方式,实现本人业务逻辑,也可以根据本人的业务搭建锁服务,

10

引用:
Quote: 引用:

你本人的方案可行:
没有,假如用C表的话本人是把C表有个订单号那一列设置唯一索引的,这样B交易插入这张表的时候是会报错的,而对于A交易是不去操作这张表的。
将插入C表的操作和插入C成功后的操作放在一个事务里就行了。

可行理论应该是可行的,就是不知道在真实的交易系统中能否是这样做的,想知道能否有更好的解决方案,这个为了一个交易而多加一张表其实感觉不太合理。

看了你上面的需求,你其实要解决的问题应该是避免请求的重复提交吧?这个重复请求的处理看你在什么地方了。
解决方案1:发送请求时控制,即请求1和请求2是同一订单号A,假设请求的原始数据为订单A,订单A发了两个请求,即请求1和请求2,需要控制住假如订单A发了一次请求后,不允许再发请求2. 在订单A发请求时,加一个锁定的状态,只允许发一次请求。
解决方案2:假如请求不受你的控制或说这个请求是其他系统的事情,他们只负责发请求,你这边要控制的话,按照你的想法,加一张表来记录这个订单号,唯一性控制。这种方法本人个人觉得挺好的。假如你要通过写代码,锁的形式就变得复杂了。


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明一个关于数据库级别的并发问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)