需求
在service层的某个方法中,在执行完一个对数据库的写方法后,抛出异常,再执行另一个对数据库的写方法,为什么不会滚呢??是对Spring的事务机制就不明白。!!
默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。
spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过
配置来捕获特定的异常并回滚
换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
解决方案:
方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)
伪代码如下:
@Transactional
public void func() {
dao.write(pojo1);
throw new Exception("异常");
dao.write(pojo2);
}
要求此时事务全部回滚,即pojo1和pojo2都不写进数据库。
单元测试代码
@Test
public void testTransactional() {
User user = new User();
user.setUid(9);
user.setUsername("李四");
user.setPassword("234");
userService.createAndUpdate(user);
}
不回滚写法
这种写法保留了createUser方法对数据库的写操作,而不执行UpdateUser方法,结果是把创建的User对象李四写进了数据库,但并没有重命名为admin。原因是抛出异常并捕获后,并没有触发事务回滚。所以代码结束后李四保留在了数据库中。
@Override
public void createAndUpdate(User user) {
try {
createUser(user);
if (!user.getPassword().equals("123")) {
throw new RuntimeException("密码不是123");
}
user.setUsername("admin");
updateUser(user);
} catch (Exception e) {
e.printStackTrace();
}
}
1
回滚写法
写法一:方法抛异常
这种写法可以在方法处抛出异常,也可以不抛出(throws RuntimeException可写可不写)。
@Override
public void createAndUpdate(User user) throws RuntimeException {
createUser(user);
if (!user.getPassword().equals("123")) {
throw new RuntimeException("密码不是123");
}
user.setUsername("admin");
updateUser(user);
}
写法二:try catch捕获异常
这种方法相比于不回滚的那种写法,只是在catch作用域内多加入了一行代码:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
1
完整方法:
@Override
public void createAndUpdate(User user) {
try {
createUser(user);
if (!user.getPassword().equals("123")) {
throw new RuntimeException("密码不是123");
}
user.setUsername("admin");
updateUser(user);
} catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
原文:https://blog.csdn.net/qq_15329947/article/details/84974302