实际开发环境中经常会遇到Spring框架配置事物失败或不起作用问题,而且无法直观的在代码中追根溯源。工程师们绞尽脑汁,检查各项配置参数、查看日志、反向推理等等手段去排除问题所在。本文就将出现最为频繁的常见问题总结分析:
目录
- 目录
- 数据库非事务支持引擎导致
- 使用context:component-scan重复扫描导致
- 事务配置错误
- 代理方法必须是公共函数(public标志)
数据库非事务支持引擎导致
使用Spring框架配置事务,其最终落实还是数据库的支持,如果项目所使用数据库不支持事务配置那自然配置失败。以MySQL为例常用的数据库引擎有InnoDB和MyISAM。其中InnoDB支持事务,MyISAM不支持。所以如果当前数据库表不是InnoDB的话需要修改过来,修改语句为:alert table [表名] type = InnoDB;
使用context:component-scan重复扫描导致
在配置文件中经常看见如下代码:
<context:component-scan base-package="com.lst.*"/>
事务的植入层一般都是通过代理类,而一般情况下这个代理类是不需要扫描的。上述代码,会将com.lst下的所有文件包统统扫描一次。所以,这时候最容易出现事务配置不起作用的问题。
建议修改方式,如:
<context:component-scan base-package="com.lst.*" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
因为我们通常会将事务层配置到Impl类中,并注解@Service注解作为代理实现类。该代码含义即为当扫描com.lst.下的所有文件包时,排除标记@Service注解代理类。这样就避免了事务不起作用问题。
事务配置错误
这类错误算是粗心或者对Spring事务配置不熟悉导致,这里我将事务基本配置写出来,可做模板参考。
1、配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
2、配置事务(注解方式)
<tx:annotation-driven transaction-manager="transactionManager" / >
2、配置事务(拦截器方式)
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" no-rollback-for="" />
<tx:method name="create*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" no-rollback-for="" />
<tx:method name="do*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" no-rollback-for="" />
<tx:method name="process*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
3、引入AOP
<aop:config>
<aop:pointcut id="transactionPointcut" expression="execution( * com.lst..service.*.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</aop:config>
代理方法必须是公共函数(public标志)
由Spring的AOP的特殊决定,入口函数必须是public,否则事务不起作用。当然这个问题实际开发中很少出现,因为定义的接口默认权限就是public。