转载自 Spring框架-事务管理注意事项
常见事务问题
-
事务不起作用
-
可能是配置不起效,如扫描问题
-
-
事务自动提交了(批量操作中)
-
可能是在没事务的情况下,利用了数据库的隐式提交
-
事务配置说明
通常情况下我们的Spring Component
扫描分为两部分,一部分是Spring Servlet(MVC)
,一部分是其他Context Config
的内容。主要扫描Annotation
定义,包括@Controller
、@Autowired
、@Resource
、@Service
、@Component
、@Repository
等。
Spring Servlet
部分的扫描配置可以通过web.xml
中DispatchServlet
的init-param
节点配置确定。
Context Config
部分的扫描配置为非以上配置的其他Spring
配置文件确定。
为了能够使用事务,需要防止因Spring Servlet
的扫描导致@Service
事务配置失效。可以调整DispatchServlet
中的配置文件,排除对@Service
的扫描。
配置如下:
<context:component-scan base-package="com.jiuyescm.xxx"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
如何通过日志判断事务是否已经被Spring所管理?
-
在logback或者log4j中对org.springframework.aop、org.springframework.transaction、org.springframework.jdbc、org.mybatis.spring.transaction进行DEBUG级别日志跟踪(开发期)
-
查看日志中是否有事务管理、开启、提交、回滚等字符,如:
DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@28cfe912] will be managed by Spring
-
没有被控制的时候,日志如下:
DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@28cfe912] will not be managed by Spring
如何通过程序判断是否存在事务?
boolean flag = TransactionSynchronizationManager.isActualTransactionActive();
返回true,则在事务控制下,否则不在控制下
什么时候做了隐式提交?
在没有容器事务的情况下,系统会尝试隐时提交。
开发建议:
-
所有Service代码中设置Class级别的@Transactional,并设置为只读,开发时可以很容易发现误数据库操作的动作。如:@Transactional(readOnly=true)。
-
所有Service代码中Public的方法设置@Transactional,并根据实际情况设置Propagation,可以设置为REQUIRED。
-
对于有异常产生可能的情况下,根据情况选择合适的rollbackFor,默认情况下可以设置对Exception.class或BizException.class进行控制。
-
尽可能减少嵌套的使用方法(Service call Service),采用传统的Controller-》Service-》Repository(DAO)的模型。
如果需要深入了解Transaction的流程,请自行翻阅和跟踪Spring和Mybatis相关代码。
以下是嵌套事务的各种情况下的执行结果(前提数据库的AutoCommit为true)
其他情况按照事务是否开启和是否抛出(捕获)对应异常来判断结果。