有关业务防重锁在项目中应用的一点探讨(包括在验证过程中遇到问题的汇总)

     最近在实际工作中遇到优化业务防重锁,在提出的新的设计方案的验证过程中遇到了许多问题,同时也学到了很多知识,现在把这些问题都记录下。

一、什么是业务防重锁

        在一些实际场景中,相同的数据在短时间内连续提交,造成数据库数据不准确的一种情况,为避免这种情况发生,才有了防重锁。比如修改某账户内余额,如果多次提交成功,就把该账户下余额相减或相加了多次,而实际是进行了一次操作,这就造成了数据的不准确。

二、目前防重锁设计思路

        目前我们项目中,采用的防重锁是加过期时间的设计思路。具体实现如下:

根据上图提到的目前防重锁存在的问题,我们需要设计新的防重锁,满足要求如下:

新的业务锁应满足的要求
    1.1、保证业务数据安全性
    1.2、防止死锁
    1.3、去掉时间设置30s
    1.4、去掉锁表残留记录
    1.5、保全、理赔、契约的加锁标志由于和业务结合紧密,无法统一加锁标志,但是可以扔放一个字段存储加锁标志

三、新的业务防重锁的设计思路

   方案一:在外层service采用事务 + 锁表唯一性约束 + 加锁(insert)解锁(delete)连续执行,实现防重复提交。
    
        具体实现: 在外层service处理业务数据前先加锁(insert),然后马上解锁操作(delete)
                    再写业务逻辑代码
                    
    方案二:在外层service采用try...catch...finally + 锁表唯一性约束,实现防重提交。
        
        具体实现:在外层service,添加try...catch...finally块,加锁操作写在try语句块之前,业务代码写在try语句块之内,
        解锁写在finally语句块之内。加锁操作内不允许异常捕获。

四、新的业务防重锁存在弊端

方案一:由于外层service加事务(spring事务注解),该层加锁解锁是在保单库,而业务处理的老核心库,
            多数据源情况下锁表上的事务是否会起作用(不会,框架为启动外层service事务)?是否会影响内层service的事务(会影响)?
    
    方案二:如果开发人员在加锁操作内捕获异常造成加锁失败了,仍执行业务代码,没有达到防重效果
    
            另外,开发人员把加锁操作放在了try语句块中,第一个请求加锁成功,在执行业务代码时,第二个相同请求进入,
            这时候第二个加锁失败或者业务异常,则执行finally删锁,这时候第一个请求还在执行,第三个相同请求进入,由于第二个删除了锁, 第三个请求会加锁成功,也会执行业务代码,未达到防重效果。

 

五、在验证过程中遇到的问题汇总(重点哦)

第一个问题:存spring+spring mvc环境下,利用声明式事务(即spring事务注解),发现事务未起作用?

      :首先我是在spring配置文件xml中未配置事务管理器、开启事务注解等,只是在方法上加了事务注解。后来把这些配置好事务仍没有起作用,原因是在spring的xml配置文件中不能配置扫描controller的。具体详解请参考下文:https://blog.csdn.net/dhklsl/article/details/87725144

第二个问题:事务的隔离级别“读已提交”一些细节

      :大家都知道oracle事务的隔离级别是:读已提交,如果修改某一个记录,但是没有commit,在另一个事务中是不能对这条记录进行修改操作,如果执行修改语句会阻塞,且执行查询语句时查询到修改前的记录。

        但是如果该表存在唯一约束字段,如果第一个事务向该表插入一条记录未提交,第二个事务也插入第一个事务中相同的记录,结果是什么样呢?估计部分人会认为第二个事务是可以插入的,因为oracle的隔离级别是读已提交,第一个事务未提交,第二个事务当然可以插入记录。答案却是第二个事务阻塞。只有当一个事务提交后,第二个事务执行插入语句,由于有唯一约束汇报违反唯一约束异常。具体原因是在事务开启时,oracle会自动加行级锁。

  

    当然,如果第二个事务插入的另外一条记录,只要不违反唯一约束条件,是可以插入的。

关于事务和锁机制的讲解及关系,可以参考下面的文章:

https://blog.csdn.net/dhklsl/article/details/87777949

https://blog.csdn.net/dhklsl/article/details/87777823

第三个问题:事务的传播行为REQUIRED一些理解

事务的传播行为required,大家都知道是:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。oracle默认采用这种传播行为。但是各位对这句话有几个做到真正的理解呢?我提几个问题,如果各位能顺利且有理有据的回答上来,说明大家都理解了。

        问题一:方法A调用方法B,A方法上没有事务,B方法上有事务,如果B方法上发生异常,A和B方法哪个会回滚还是都回滚?如果是A方法上发生异常,A和B方法哪个会回滚还是都回滚?

       问题二:方法A调用方法B,A方法和B方法上都有事务,如果B方法上发生异常,A和B方法哪个会回滚还是都回滚?如果是A方法上发生异常,A和B方法哪个会回滚还是都回滚?

       问题三:方法A调用方法B,A方法上有事务,B方法上没有事务,如果B方法上发生异常,A和B方法哪个会回滚还是都回滚?如果是A方法上发生异常,A和B方法哪个会回滚还是都回滚?

  如果这三个问题回答不上来的同学,请务必详细认真阅读下面的文章,这是我见过对事务的传播行为讲解最清楚的文章了。

     https://blog.csdn.net/dhklsl/article/details/87625166

第四个问题:关于InitializingBean接口下afterPropertiesSet方法的认知

  其实关于这个InitializingBean接口,我以前的文章中有过讲解,但是由于时间长了,不怎么见到就给遗忘了,所以这次再总结下。

   首先这是一个初始化接口,当bean实现该接口并实现了afterPropertiesSet方法。当该bean被spring创建时,会先执行afterPropertiesSet方法中的代码,然后在执行bean注入时配置init-method中配置的方法。主要作用是在某个bean被创建前需要做一些初始化工作,就会用到这个方法。

<bean id="testInitializingBean" class="com.TestInitializingBean" init-method="testInit"></bean>

具体关于这个接口的讲解,请参考下面文章:

https://blog.csdn.net/dhklsl/article/details/86478881

第五个问题:spring配置文件xml中利用<bean>注入的bean不起作用的问题

   一般有几种情况会造成bean注入失败:

    一是spring的xml配置文件中包扫描路径配置错误

二是web.xml文件中spring监听器路径配置错误

但是我的问题比较奇怪,是利用注解@Service等注解是没问题的,但是在springxml文件中用bean注入就不行。原因是我用idea建maven+spring环境时,手动创建resources文件夹时,没有写s,造成这个问题,同时也没有报文件路径错误。

我的理解,如果这个文件名字错了,会报找不到applicationContext-spring.xml这个配置文件,但是没有报找不到文件错误,且注解是可以使用的,所以我就确定不是路径问题。但是在我重新搭建环境时发现了这个细节,把原环境中resource加上s,问题解决,所以这是一个比较难找的原因。

 

第六个问题:spring框架提供的事务注解@Transactional的一些新认识

第一,这个注解只对public方法有效,如果非public方法上加了该注解也没有事务,但是也不会报错

第二,这个注解如果没有指定value值,将默认使用“transationManager”命名对应的事务管理器
在配置文件中,默认情况下,<tx:annotation-driven>会自动使用名称为transactionManager的事务管理器。所以,如果定义的事务管理器名称为transactionManager,那么就可以直接使用<tx:annotation-driven/>
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一路奔跑1314

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值