南京网站设计 联络南京乐识,建筑企业资质查询系统,h5案例,公众号seo排名优化一、背景
在日常开发中#xff0c;经常有需要使用事务来保证数据一致性的情况。简单点的话直接在方法上面加Transactional注解就可以了。 但这样存在一个问题#xff0c;在整个业务方法层面加注解会把很多并不需要归入事务的操作也归入到了事务里面#xff0c;这样会可能会…一、背景
在日常开发中经常有需要使用事务来保证数据一致性的情况。简单点的话直接在方法上面加Transactional注解就可以了。 但这样存在一个问题在整个业务方法层面加注解会把很多并不需要归入事务的操作也归入到了事务里面这样会可能会出现大事务的情况影响系统性能。 为了提高系统性能比较好的一种方案是只把操作数据库的部分代码放到一个方法给这个小方法加上事务这样基本不会出现大事务的问题。而要实现这种方案会碰上很常见的一种事务失效的场景。
二、事务失效场景
serviceImpl层
Service
public class SdSchoolCallRecordServiceImpl extends ServiceImplSdSchoolCallRecordMapper, SdSchoolRlyCallRecord implements ISdSchoolCallRecordService {OverrideTransactional(rollbackFor Exception.class)public boolean test1() {SdSchoolRlyCallRecord callRecordnew SdSchoolRlyCallRecord();callRecord.setCallReason(2);this.save(callRecord);int a10/0;SdSchoolRlyCallRecord callRecord1new SdSchoolRlyCallRecord();callRecord1.setCallReason(6);this.save(callRecord1);return true;}Overridepublic boolean testTran1() {return this.test1();}
}Controller层 GetMapping(value /tes1)ApiOperation(value tes1, notes tes1)public Result? tes1() {sdSchoolCallRecordService.testTran1();return null;}调用接口看数据库多了一条记录事务回滚失败。
三、新方式调用
ServiceImpl层为了区分把值换成1
Service
public class SdSchoolCallRecordServiceImpl extends ServiceImplSdSchoolCallRecordMapper, SdSchoolRlyCallRecord implements ISdSchoolCallRecordService {//注入自身Resourceprivate ISdSchoolCallRecordService sdSchoolCallRecordService;OverrideTransactional(rollbackFor Exception.class)public boolean test1() {SdSchoolRlyCallRecord callRecordnew SdSchoolRlyCallRecord();callRecord.setCallReason(1);this.save(callRecord);int a10/0;SdSchoolRlyCallRecord callRecord1new SdSchoolRlyCallRecord();callRecord1.setCallReason(5);this.save(callRecord1);return true;}Overridepublic boolean testTran1() {//采用对象的方式调用方法return sdSchoolCallRecordService.test1();}
}Controller层没有变化。
调用接口查看数据库没有记录事务成功回滚。
四、解析
Spring事务是通过动态代理实现的而内部方法调用不走动态代理因而方法上的注解就无法生效。因为这个事务注解对应的类必须加上Component或Service注解。 既然需要动态代理才能使用那么针对这种方式如果我们在类里面注入自身然后通过对象调用不就也可以将事务交给事务管理器管理。调用方式也就和普通事务能生效的Service方法一样。