java - Spring事务配置在service层,传播规则为required,方法中究竟应该是调用service还是多个dao比较好?
问题描述
Spring中事务配置如下:
<tx:advice transaction-manager='transactionManager'> <tx:attributes><tx:method name='delete*' propagation='REQUIRED' read-only='false' rollback-for='java.lang.Exception'/><tx:method name='insert*' propagation='REQUIRED' read-only='false' rollback-for='Exception' /><tx:method name='update*' propagation='REQUIRED' read-only='false' rollback-for='java.lang.Exception' /><tx:method name='save*' propagation='REQUIRED' read-only='false' rollback-for='Exception' /><tx:method name='*' propagation='REQUIRED' read-only='true'/> <:attributes><:advice>
现在ServiceA中有一个方法methodA,那么在ServiceA中应该注入ServiceB,ServiceC呢,还是DaoB,DaoC,然后在methodA中去保存B,C,保证B,C同时保存成功,或同时失败!
答:
既可以单独注入service,也可以单独注入dao,关键是,spring容器的事务管理默认只截获未检查异常RuntimeException。上边配置的rollback-for='java.lang.Exception'其实不用配置。配置如下
<tx:advice transaction-manager='transactionManager'> <tx:attributes><tx:method name='delete*' propagation='REQUIRED' read-only='false' /><tx:method name='insert*' propagation='REQUIRED' read-only='false' /><tx:method name='update*' propagation='REQUIRED' read-only='false' /><tx:method name='save*' propagation='REQUIRED' read-only='false' /><tx:method name='*' propagation='REQUIRED' read-only='true'/> <:attributes><:advice>
解决方案是:
如果代码中使用了try...catch...捕获了检查型异常,意味着程序员自己必须要解决异常,必须知道如何解决异常。通常的做法是:将检查型的异常在catch块中重新抛出为Runtime Exception,这样Spring容器就会截获该异常,进行事务回滚处理 。如下
try { .....}catch( CheckedException e ) { logger.error(e); throw new RuntimeException(e);}
注意,不使用try...catch...,而在方法签名后向外抛出检查型异常的行为不可取,事务也不会回滚。
如果代码中没有使用try抛出了未检查异常,则Spring容器会自动截获异常,进行事务回滚处理。
问题解答
回答1:如果你想更多了解Spring事务机制可以看我的这几篇文章:
Spring Transaction详解 - Transaction Isolation
Spring Transaction详解 - Transaction Propagation模式
Spring Transaction详解 - 手动回滚事务
Spring Transaction详解 - 异常发生时的事务回滚机制
回答2:其实这种事情就是根据需要了,事务是会自动合并的,但作为设计考虑,尽量调用 dao 这样能够使不同的 service 得以解偶。
回答3:一般我们在Service的方法上会进行事务的定义,特别是如果有控制传播行为的场景,那放入dao就和放入service不同了。因为dao肯定都是在一个大事务下了,service就比较复杂了。