在我们常规的开发过程中,想必大家都有听过或者用过事务,以前的springmvc当中大家会是创建相应的xml事务配置文件,声明式的策略去对指定的特定的操作或者数据源做事务管理,后来大家了解通过配置切面(PointCut)应用到相应的业务方法上或者直接在方法上加@Ttransactional注解。
开发场景:
在实际开发过程中我们习惯性的将第三方资源(第三方接口、缓存等)或数据库视为数据源,定义一个业务service类去实现某一个复杂的功能,其中有对数据库多张表进行增删改,亦有对缓存或者第三方接口调用共同完成业务处理,在此我们无法决定第三方业务接口的性能,如果说我们在同时对3个表做增删改操作,又去调用第三方接口查询数据,同时还增加查询自身业务数据库数据,以防数据不一致性,我们在开发中会考虑使用事务托管。
存在隐患:
当数据源连接设置为30时,而在1秒内有50个人操作,而在此时,就出现问题了,服务会抛出CannotGetJdbcConnectionException异常,导致此异常的原因是多用户访问,数据库资源分配不够。
为什么会数据库资源分配不够呢?
原因就是我们在方法上面使用的@Ttransactional注解导致的,可以去查看相应的实现源码,它是通过aop的方式实现,进入方法是并开启了一个事务,直到业务执行成功后就提交事务,业务执行失败就做回滚操作。如果说我们在操作自身的数据库需要消耗50毫秒,而调用第三方接口时需要消耗1秒,调用缓存服务需要消耗20毫秒,那么在此操作我们就需要总消耗1秒零70毫秒,而此时我们启用了事务托管,那么数据库连接是一直在占用的,一个用户访问就占用1秒70毫秒,那么在50个用户访问时,就的在1秒70毫秒内占用50个数据库连接,而我们的数据源连接配置的30个,由此就知道数据库配置不够。
为了解决以上的问题,今天向大家介绍的是编程式事务-TransactionTemplate。
将我们的业务细分,需要使用事务管理的就用事务,而不需要事务的时候则不用。
代码使用(案例):
@Autowired private TransactionTemplate template;
/** * 1、修改用户状态 * 2、修改用户办理信息 * 3、发送短信 * 4、获取最新的数据返回用户 * ... * @auth wangzr * @param user 会员用户信息 */ public void handle(TSysUser user){ Boolean flag = false; flag = template.execute(new TransactionCallback<Boolean>() { @Override public Boolean doInTransaction(TransactionStatus transactionStatus) { int handleNum = 0; try{ // 修改某某业务办理信息 // TODO CODE.... handleNum++; // 修改用户状态 // TODO CODE ... handleNum++; }catch(Exption){
e.printStackTrace(); // 手动回滚事务 transactionStatus.setRollbackOnly();} return handleNum == 2; } }); if (flag) { // 调用发送短信服务 sendMsg(new String[]{user.getMobile()}, "办理成功"); // 更新缓存 // TODO CODE... // 查询相关信息返回用户 // TODO CODE ... } }