背景:
一个spring老项目,遇到使用@Transactional事务不起作用问题,这里记录一下。
最开始在类上加@Transactional注解
@Transactional
public class Test {
...
}
把@Transactional注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。 使用@Transactional 不指定 rollback-for对应异常类,默认抛出 RuntimeException异常时才会回滚,try catch捕获异常不会回滚。
尝试一把抛RuntimeException异常数据依然创建成功,事务没有起作用。
经过一番排查,发现spring-content.xml对事务的配置默认所有操作都不开启事务
部分配置截取
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="load*" read-only="true" />
<tx:method name="get*" read-only="true" />
<tx:method name="select*" read-only="true" />
<tx:method name="create*" propagation="NOT_SUPPORTED"
rollback-for="java.lang.Exception" />
</tx:attributes>
</tx:advice>
配置文件不好更改,不过@Transactional颗粒度支持类或者方法配置。
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class Test {
...
}
这样事务就生效了,目标方法中抛出的异常是 rollbackFor 指定的异常的子类,事务同样会回滚。
有时我们不能直接暴露异常,就需要手动回滚。代码:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();。
比如
try {
...
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
...
}
Spring 支持两种类型的事务管理,分别是编程式和声明式。上面提到使用注解 @Transactional 为声明式事务。
使用声明式事务,对于公用方法生效,事务管理范围为整个方法。如果需要颗粒度更小的管理事务,需要编程式介入,编程式需要手动维护事务,但也更灵活。
示例代码:
@Autowired
PlatformTransactionManager transactionManager;
public void create(String name, Integer age, Integer marks, Integer year){
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL1, name, age);
// Get the latest student id to be used in Marks table
String SQL2 = "select max(id) from Student";
int sid = jdbcTemplateObject.queryForInt( SQL2 );
String SQL3 = "insert into Marks(sid, marks, year) " +
"values (?, ?, ?)";
jdbcTemplateObject.update( SQL3, sid, marks, year);
System.out.println("Created Name = " + name + ", Age = " + age);
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(status);
throw e;
}
return;
}
参考文档