1. 开启事务支持
只需要通过 @EnableTransactionManagement
注解就可以开启声明式事务的支持,提供的可选值有:
proxyTargetClass
:表示 AOP 代理是基于接口的还是基于类的,默认是基于接口代理。mode
:如果是有接口的话可以使用PROXY
,如果没有接口的话可以使用ASPECTJ
利用CgLib
对类做增强。order
:指定事务拦截的顺序,默认是最低的优先级,这样可以保证其他的代理类是在事务开启之后执行。
2. @Transactional
开启了对事务注解的支持之后,我们就可以在需要的类或者方法上面添加 @Transactional
注解,@Transactional
注解的话也有一些设置的项。
4.1 transactionManager
默认的话就是 DataSourceTransactionManager
。
4.2 propagation
事务的传播机制,默认的话是 REQUIRED
,多个方法调用共享同一个事务。
4.3 isolation
事务的隔离级别,这个跟使用的数据库有关系,默认的话是使用数据库默认的隔离级别。
4.4 timeout
事务超时时间。
4.5 readOnly
是否只读。
4.6 rollbackFor
在类或者方法中抛出的异常与 rollbackFor
中指定的异常 instanceof
返回 true
的情况下会回滚事务。
4.7 rollbackForClassName
与 rollbackFor
类似,只不过指定的是异常的名称。
4.8 noRollbackFor
遇到指定的异常时候不会回滚事务
4.9 noRollbackForClassName
与 noRollbackFor
类似,只不过指定的是异常的名称。
3. 没有通过代理对象执行
在 Spring
当中,声明式事务其实是为类做了一个代理,既然是代理类,也就是说需要去调用代理类才能够执行到需要被增强的方法,如果是在方法内部做调用的话,也就是没有走到代理方法或者说没有做增强处理,例如:
@Component
public class FooServiceImpl implements FooService {
@Override
@Transactional(rollbackFor = RollbackException.class)
public void insertThenRollback() throws RollbackException {
this.jdbcTemplate.execute("INSERT INTO FOO (BAR) values('BBB')");
throw new RollbackException();
}
@Override
public void invokeInsertThenRollback() throws RollbackException {
this.insertThenRollback();
}
}
@Override
public void run(String... args) throws Exception {
try {
this.fooService.invokeInsertThenRollback();
} catch (RollbackException e) {
// ignore.
}
log.info("bbb: {}.", this.countByBAR("BBB"));
}
日志输出如下:
bbb: 1.
要解决这个问题我们可以有以下几种方式:
3.1 通过当前代理对象调用自身实例
@Override
public void invokeInsertThenRollback() throws RollbackException {
((FooService) AopContext.currentProxy()).insertThenRollback();
}
3.2 注入自身实例
@Autowired
private FooService fooService;
@Override
public void invokeInsertThenRollback() throws RollbackException {
this.fooService.insertThenRollback();
}
3.3 再加一层事务
@Override
@Transactional(rollbackFor = RollbackException.class)
public void invokeInsertThenRollback() throws RollbackException {
this.insertThenRollback();
}
4. 不能对目标方法增强
@Transactional
只能支持 public
修饰方法,否则事务会失效,官方文档地址:Spring官方文档:声明式事务方法可见性
@Autowired
private FooServiceImpl fooService;
public void invokeInsertThenRollback() throws RollbackException {
this.fooService.insertThenRollback();
}
@Transactional(rollbackFor = RollbackException.class)
protected void insertThenRollback() throws RollbackException {
this.jdbcTemplate.execute("INSERT INTO FOO (BAR) values('BBB')");
throw new RollbackException();
}
5. rollbackException与抛出的异常返回false
@Transactional
注解默认回滚异常是 RuntimeException
级别的异常,也就是非受检异常,如果是遇到了受检异常那么事务不会回滚:
public class RollbackException extends Exception {
}
@Transactional
public void insertThenRollback() throws RollbackException {
this.jdbcTemplate.execute("INSERT INTO FOO (BAR) values('BBB')");
throw new RollbackException();
}
public void invokeInsertThenRollback() throws RollbackException {
this.fooService.insertThenRollback();
}
6. progagtion的选择问题
比如以下方法返回统计的 BBB
是 1,有一条被回滚,有一条被成功执行。
@Override
@Transactional(rollbackFor = RollbackException.class,propagation = Propagation.REQUIRES_NEW)
public void insertThenRollback() {
this.jdbcTemplate.execute("INSERT INTO FOO (BAR) values('BBB')");
}
@Override
@Transactional(rollbackFor = RollbackException.class)
public void invokeInsertThenRollback() throws RollbackException {
this.jdbcTemplate.execute("INSERT into FOO (BAR) values('BBB')");
this.fooService.insertThenRollback();
throw new RollbackException();
}