SpirngBoot Transactional 处理
在SpingBoot下使用事务很简单只要在class或function的上打个标签 @Transactional 就可以了。
Transactional 是Sring AOP去管理的,这个很重要,所有的坑都是因为不了解这个才会踩下去。但好多同学其实跟我一样对AOP不怎么了解的,所以我把我走过的坑都分享一下。
下面是我走过的坑。
1. @Transactional 标签可以打在class上,也可以打在function上,function的话必须为public,而且这个function是被其它class掉用才会生效。简单说就是,如果在class内的function互相调用就别妄想事务会回滚;
2. 关于回滚的触发是方法抛出RuntimeException,并且RuntimeException未被捕获,这个时候就会自己回滚,如果你使用了try-catch,异常都被catch了,你就别妄想事务会回滚;
3. 真的想在catch里面自己回滚吗,还是有的,你必须抛出RuntimeException,如果抛出的是Exception,则需要使用@Transactional(rollbackFor=Exception.class)处理指定的Excetption;
4. 你不要抛出异常但也要回滚?还是有的,你就要手动回滚:“ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); ”;
5. 有没有同学像我一样,在回滚以后还要写数据库记录失败的状态,我要说明一下,回滚是切面回滚,即使你在rollback后面的代码也是不生效的;
6. 针对这一点,我用了一个很简单的解决思路,在这个打上@Transactional 标签的class里面加一个方法去处理failed的方法就好;
因为需要回滚的方法必须是被其它类调用才能触发事务,所以在调用它的地方你可以用try-catch,在捕获Excetption以后再调用failed方法就好了;
7. 其实还有一个参数是可以选择的@Transactional (propagation=Propagation.REQUIRES_NEW), 把这个标签打在failed上面就可以了
我还是写个Demo吧:
1. 什么都不做,最简单的事务处理
package org.bts.services; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class TransactionalService { public void save() { } public void failed() { } }
package org.bts.services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class TransactionalDemo { @Autowired private TransactionalService service; public void demo() { try { service.save(); } catch (Exception e) { e.printStackTrace(); service.failed(); } } }
以上这个其实save里面就会自己动做回滚了
2. 如果你要用try-catch, 以下为三种处理方式
package org.bts.services; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class TransactionalService { public void Save() { try { } catch (Exception e) { throw new RuntimeException(); } } public void failed() { } }
package org.bts.services; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @Service @Transactional public class TransactionalService { public void Save() { try { } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } } public void failed() { } }
package org.bts.services; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional(rollbackFor=Exception.class) public class TransactionalService { public void Save() { try { } catch (Exception e) { e.printStackTrace(); throw e; } } public void failed() { } }
3.使用Propagation.REQUIRES_NEW
package org.bts.services; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional(rollbackFor=Exception.class) public class TransactionalService { public void Save() { try { } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); failed(); } } @Transactional(propagation=Propagation.REQUIRES_NEW) public void failed() { } }