Spring 事务
- 数据库事务是企业应用中最为重要的内容之一。
- 事务往往会涉及到注释@Transactional
1. Spring的数据管理器的设计
- 在Spring中数据库事务是通过
PlatformTransactionManager
进行管理的,而能够支持事务的是org.springframework.transaction.support.TransactionTemplate
,它是Spring所提供的事务管理器的模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| private PlatformTransactionManager transactionManager; ...... @Override public <T> T execute(TransactionCallback<T> action) throws TransactionException{ if(this.transactionManager instanceof CallbackPreferringPlatformTransactionManager){ return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this,action); }else{ TransactionStatus status = this.transactionManager.getTransaction(this); T result; try{ result = action.doInTransaction(status); }catch(RuntimeException ex){ rollbackOnException(status, ex); throw ex; }catch(Error ex){ rollbackOnException(status, err); throw err; }catch(Throwable ex){ rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } }
|
- 事务的创建、提交和回滚是通过
PlatformTransactionManager
接口来完成。
- 当事务产生异常时会回滚事务,在默认的实现中所有的异常都会回滚,可以通过配置去修改在某些异常发生时回滚或者不会滚事务。
- 当无异常时,会提交事务。
- 多种事务管理器如下
1.1. 数据管理器分类
- 可以看到多个数据库管理器,并且支持JTA事务,常用的是
DataSourceTransactionManager
,集成抽象事务管理器AbstractPlatformTransactionManager
,而AbstractPlatformTransactionManager
又实现了PlatformTransactionManager
。这样Spring就可以如同源码中那样使用PlatformTransactionManager
接口的方法,创建、提交或者回滚事务了。
PlatformTransactionManager
接口的源码如下:
1 2 3 4 5 6 7 8
| public interface PlatformTransactionManager{ TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
|
2. 通过标签来完成Spring的事务回滚
- 将所有的对于数据库的操作都放置到一个被@Transactional标记的Service方法中可以全部回滚
1 2 3 4 5 6 7 8 9 10 11 12
| @Transactional public boolean UserRegister(ESysUser entity) { try { eSysUserDao.insert(entity); } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); log.error(e.getMessage(), e); return false; } }
|
2.1. 根据异常进行回滚
@Transactional(rollbackFor = { Exception.class})
- 没有捕获异常,则会抛出异常,则将doDbStuff1()中的数据库操作进行回滚。
1 2 3 4 5
| @Transactional(rollbackFor = { Exception.class }) public void test() throws Exception { doDbStuff1(); doDbStuff2(); }
|
- 如果在程序中自已捕获异常未往外抛,如下代码事务不会回滚
1 2 3 4 5 6 7 8 9
| @Transactional(rollbackFor = { Exception.class }) public void test() { try { doDbStuff1(); doDbStuff2(); } catch (Exception e) { e.printStackTrace(); } }
|
- 既要捕获异常,又要回滚
1 2 3 4 5 6 7 8 9 10 11
| @Transactional(rollbackFor = { Exception.class }) public void test() { try { doDbStuff1(); doDbStuff2(); } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return; } }
|
2.2. 回滚部分异常
- 使用
Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
设置回滚点。
- 使用
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
回滚到savePoint。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Transactional(rollbackFor = Exception.class) @Override public void saveEntity() throws Exception{ Object savePoint = null; try { userDao.saveUser(); savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); studentDao.saveStudent(); int a = 10/0; }catch (Exception e){ System.out.println("异常了=====" + e); TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint); } }
|
3. 参考
- 【Java EE】深入Spring数据库事务管理
- spring事务回滚:当同时需要在多个数据表插入数据时,一个出错如何实现全部回滚
- Spring中抛出异常时,既要要返回错误信息,还要做事务回滚
- SpringBoot事务简单操作及手动回滚