上一篇文章讲解了获取事务,并通过获取的connection设置只读,隔离级别等;这篇文章讲事务剩下的回滚和提交。

事务的回滚处理

之前已经完成了目标方法运行前的事务准备工作。而这些准备工作的最大目的无非就是对于程序没有按照我们期待的那样进行,也就是出现特定的错误;那么当出现错误的时候Spring是怎么对数据进行恢复的呢?我们先来看一下TransactionAspectSupport类里的invokeWithinTransaction函数的completeTransactionAfterThrowing方法(其它的已经在上一篇文章讲解过,这里不再赘述):

  • 看源码(TransactionAspectSupport.java)
  1. protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
  2. // 当抛出异常时,先判断当前是否存在事务,这是基础依据
  3. if (txInfo != null && txInfo.getTransactionStatus() != null) {
  4. if (logger.isTraceEnabled()) {
  5. logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
  6. "] after exception: " + ex);
  7. }
  8. // 这里判断是否回滚默认的 依据是抛出的异常是RunTimeException 或者是 Erro 类型r
  9. if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
  10. try {
  11. txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
  12. }
  13. catch (TransactionSystemException ex2) {
  14. logger.error("Application exception overridden by rollback exception", ex);
  15. ex2.initApplicationException(ex);
  16. throw ex2;
  17. }
  18. catch (RuntimeException | Error ex2) {
  19. logger.error("Application exception overridden by rollback exception", ex);
  20. throw ex2;
  21. }
  22. } else {
  23. // We don't roll back on this exception.
  24. // Will still roll back if TransactionStatus.isRollbackOnly() is true.
  25. // 如果不满足回滚条件,即使抛出异常也正常提交
  26. try {
  27. txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  28. }
  29. catch (TransactionSystemException ex2) {
  30. logger.error("Application exception overridden by commit exception", ex);
  31. ex2.initApplicationException(ex);
  32. throw ex2;
  33. }
  34. catch (RuntimeException | Error ex2) {
  35. logger.error("Application exception overridden by commit exception", ex);
  36. throw ex2;
  37. }
  38. }
  39. }
  40. }
  • 源码分析

在对目标方法的执行过程中,一旦出现Throwable就会被引导至此方法进行处理,但是不意味着所有的Throwable都会被回滚处理;比如我么最常用的Exception,默认是不会被处理的,默认情况下,即使出现异常,数据也会被正常提交,而这个关键的地方就在于txInfo.transactionAttribute.rollbackOn(ex)这个函数:

回滚条件
  • 看源码(DefaultTransactionAttribute.java)
  1. @Override
  2. public Boolean rollbackOn(Throwable ex) {
  3. return (ex instanceof RuntimeException || ex instanceof Error);
  4. }
  • 源码分析

从上述代码中可以看到,默认情况下:Spring只会对RuntimeExceptionError两种类型的情况进行处理;但是我们可以利用注解方式来改变。例如:

  1. @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
回滚处理

当然,一旦符合回滚条件,那么Spring就会将程序引导至回滚处理函数中。接下来我们看一下回滚函数,也就是txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());代码的rollback方法:

  • 看源码(AbstractPlatformTransactionManager.java)
  1. @Override
  2. public final void rollback(TransactionStatus status) throws TransactionException {
  3. if (status.isCompleted()) {
  4. throw new IllegalTransactionStateException(
  5. "Transaction is already completed - do not call commit or rollback more than once per transaction");
  6. }
  7. DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
  8. processRollback(defStatus, false);
  9. }

看一下这个方法里面的processRollback函数:

  • 看源码(AbstractPlatformTransactionManager.java)
  1. private void processRollback(DefaultTransactionStatus status, Boolean unexpected) {
  2. try {
  3. Boolean unexpectedRollback = unexpected;
  4. try {
  5. triggerBeforeCompletion(status);
  6. // 如果status 有 savePoint , 说明此事务 是 PROPAGATION_NESTED 且为子事务,只能回滚到savePoint
  7. if (status.hasSavepoint()) {
  8. if (status.isDebug()) {
  9. logger.debug("Rolling back transaction to savepoint");
  10. }
  11. // 回滚到保存点
  12. status.rollbackToHeldSavepoint();
  13. }
  14. // 如果此时的status显示的是新的事务,才进行回滚 else if (status.isNewTransaction()) {
  15. if (status.isDebug()) {
  16. logger.debug("Initiating transaction rollback");
  17. }
  18. // 如果此时是子事务,我们在这里想想哪些类型的事务会进到这里
  19. // 回滚之前说的 已经存在的事务的处理,
  20. // PROPAGATION_NOT_SUPPORTED 创建的事务:
  21. // return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);
  22. // 说明是旧事务,并且事务为null 不会进入
  23. // PROPAGATION_REQUIRES_NEW 创建一个新的子事务,
  24. // newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
  25. // 说明是新事务 ,会进入这个分支
  26. // PROPAGATION_NESTED 创建的Status是 prepareTransactionStatus(definition, transaction, false...)是旧事物,
  27. // 使用的是外层的事务,不会进入
  28. // PROPAGATION_SUPPORTS 或 PROPAGATION_REQUIRED或PROPAGATION_MANDATORY存在事务加入事务即可,
  29. // 标记为旧事务,prepareTransactionStatus(definition, transaction, false..)
  30. // 说明当子事务,只有REQUIRES_NEW会进入到这里进行回滚
  31. doRollback(status);
  32. } else {
  33. // Participating in larger transaction
  34. // 如果status中有事务,进入下面
  35. // 根据上面分析,PROPAGATION_SUPPORTS 或 PROPAGATION_REQUIRED或PROPAGATION_MANDATORY
  36. // 创建的Status是prepareTransactionStatus(definition, transaction, false..)
  37. // 如果此事务时子事务,表示存在事务,并且事务为旧事物,将进入到这里
  38. if (status.hasTransaction()) {
  39. if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
  40. if (status.isDebug()) {
  41. logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
  42. }
  43. // 对status中的transaction作一个回滚了的标记,并不会立即回滚
  44. doSetRollbackOnly(status);
  45. } else {
  46. if (status.isDebug()) {
  47. logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
  48. }
  49. }
  50. } else {
  51. logger.debug("Should roll back transaction but cannot - no transaction available");
  52. }
  53. // Unexpected rollback only matters here if we're asked to fail early
  54. if (!isFailEarlyOnGlobalRollbackOnly()) {
  55. unexpectedRollback = false;
  56. }
  57. }
  58. }
  59. catch (RuntimeException | Error ex) {
  60. triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
  61. throw ex;
  62. }
  63. triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
  64. // Raise UnexpectedRollbackException if we had a global rollback-only marker
  65. if (unexpectedRollback) {
  66. throw new UnexpectedRollbackException(
  67. "Transaction rolled back because it has been marked as rollback-only");
  68. }
  69. }
  70. finally {
  71. // 清空记录的资源并将挂起的资源恢复
  72. // 子事务结束了,之前挂起的事务就要恢复了
  73. cleanupAfterCompletion(status);
  74. }
  75. }

我们先看看processRollback函数里面的status.rollbackToHeldSavepoint();这段代码,回滚到保存点的代码,根据保存点回滚的实现方式其实是根据底层的数据库连接进行的。回滚到保存点之后,也要释放掉当前的保存点。看具体实现:

  • 看源码(AbstractTransactionStatus.java)
  1. public void rollbackToHeldSavepoint() throws TransactionException {
  2. Object savepoint = getSavepoint();
  3. if (savepoint == null) {
  4. throw new TransactionUsageException(
  5. "Cannot roll back to savepoint - no savepoint associated with current transaction");
  6. }
  7. getSavepointManager().rollbackToSavepoint(savepoint);
  8. getSavepointManager().releaseSavepoint(savepoint);
  9. setSavepoint(null);
  10. }
  • 源码分析

这里使用的是JDBC的方式进行的数据库连接,那么getSavepointManager()函数返回的是JdbcTransactionObjectSupport,也就是说上面函数会调用JdbcTransactionObjectSupport 中的 rollbackToSavepoint 方法。

接下来查看一下JdbcTransactionObjectSupport 中的 rollbackToSavepoint 方法。

  • 看源码(JdbcTransactionObjectSupport.java)
  1. @Override
  2. public void rollbackToSavepoint(Object savepoint) throws TransactionException {
  3. ConnectionHolder conHolder = getConnectionHolderForSavepoint();
  4. try {
  5. conHolder.getConnection().rollback((Savepoint) savepoint);
  6. conHolder.resetRollbackOnly();
  7. }
  8. catch (Throwable ex) {
  9. throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
  10. }
  11. }

当之前已经保存的事务信息中的事务为新事务,那么直接回滚。常用于单独事务的处理。对于没有保存点的回滚,Spring同样是使用底层数据库连接提供的API来操作的。由于我们使用的是DataSourceTransactionManager,所以AbstractPlatformTransactionManager里的processRollback函数里的doRollback(status);也就是在DataSourceTransactionManager实现的。

  • 看源码(DataSourceTransactionManager.java)
  1. @Override
  2. protected void doRollback(DefaultTransactionStatus status) {
  3. DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  4. Connection con = txObject.getConnectionHolder().getConnection();
  5. if (status.isDebug()) {
  6. logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
  7. }
  8. try {
  9. con.rollback();
  10. }
  11. catch (SQLException ex) {
  12. throw translateException("JDBC rollback", ex);
  13. }
  14. }

当前事务信息中表明是存在事务的,又不属于以上两种情况,只做回滚标识,等到提交的时候再判断是否又回滚标识,下面回滚的时候再介绍,子事务中状态为PROPAGATION_SUPPORTS PROPAGATION_REQUIREDPROPAGATION_MANDATORY回滚的时候将会标记为回滚标识,我们先来看看是怎么标记的。回到AbstractPlatformTransactionManager类的processRollback函数的doSetRollbackOnly(status);

  • 看源码(DataSourceTransactionManager.java)
  1. @Override
  2. protected void doSetRollbackOnly(DefaultTransactionStatus status) {
  3. // 将status中的transaction取出
  4. DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  5. if (status.isDebug()) {
  6. logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
  7. "] rollback-only");
  8. }
  9. // transaction执行标记回滚
  10. txObject.setRollbackOnly();
  11. }

继续查看一下setRollbackOnly()函数:

  • 看源码(DataSourceTransactionManager.java)
  1. public void setRollbackOnly() {
  2. // 这里将transaction里面的connHolder标记回滚
  3. getConnectionHolder().setRollbackOnly();
  4. }

继续查看setRollbackOnly()的具体实现

  • 看源码(ResourceHolderSupport.java)
  1. public void setRollbackOnly() {
  2. // 将holder中的这个属性设置成true
  3. this.rollbackOnly = true;
  4. }

我们看到将status中的Transaction中的ConnectionHolder的属性rollbackOnly属性设置为true,这里暂时不多考虑,等到下面提交的时候再介绍。

简单小结

简单总结一下AbstractPlatformTransactionManager类的processRollback函数

  • status.hasSavepoint() ** 如果status中有savePoint,只回滚到savePoint!**
  • status.isNewTransaction() 如果status是一个新事务,才会真正去回滚!
  • status.hasTransaction() ** 如果status有事务,将会对staus中的事务标记!**

事务的提交

在事务的执行没有出现任何的异常,也就意味着事务可以走正常事务的提交流程,这里回到流程中,看看TransactionAspectSupport类中的commitTransactionAfterReturning(txInfo);函数具体做了什么

  • 看源码(TransactionAspectSupport.java)
  1. protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
  2. if (txInfo != null && txInfo.getTransactionStatus() != null) {
  3. if (logger.isTraceEnabled()) {
  4. logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
  5. }
  6. txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  7. }
  8. }
  • 源码分析

在真正的数据提交之前,还需要做一个判断,不知道大家还有没有印象,在我们分析事务异常处理规则的时候,当某个事务既没保存点,又不是新事务,Spring对它的处理方式只是设置一个回滚标识(具体是在AbstractPlatformTransactionManager的processRollback函数里面)。这个标识在这里就会派上用场了,如果子事务状态是PROPAGATION_SUPPORTS PROPAGATION_REQUIREDPROPAGATION_MANDATORY,将会在外层事务中运行,回滚的时候,并不执行回滚,只是标记一下回滚的状态,当外层事务提交的时候,会先判断ConnectionHolder中的回滚状态,如果已经标记为回滚,则不会提交,而是外层事务进行回滚。(查看一下txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());)的commit方法:

  • 看源码(AbstractPlatformTransactionManager.java)
  1. @Override
  2. public final void commit(TransactionStatus status) throws TransactionException {
  3. if (status.isCompleted()) {
  4. throw new IllegalTransactionStateException(
  5. "Transaction is already completed - do not call commit or rollback more than once per transaction");
  6. }
  7. DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
  8. // 如果在事务链中已经被标记回滚,那么不会尝试提交事务,直接回滚
  9. if (defStatus.isLocalRollbackOnly()) {
  10. if (defStatus.isDebug()) {
  11. logger.debug("Transactional code has requested rollback");
  12. }
  13. processRollback(defStatus, false);
  14. return;
  15. }
  16. if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
  17. if (defStatus.isDebug()) {
  18. logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
  19. }
  20. // 这里会进行回滚,并且抛出一个异常
  21. processRollback(defStatus, true);
  22. return;
  23. }
  24. // 如果没有被标记回滚之类的,这里才真正判断是否提交
  25. processCommit(defStatus);
  26. }

当事务执行一切都正常的时候,就可以真正的进入到提交流程了。

  • 看源码(AbstractPlatformTransactionManager.java)
  1. private void processCommit(DefaultTransactionStatus status) throws TransactionException {
  2. try {
  3. Boolean beforeCompletionInvoked = false;
  4. try {
  5. Boolean unexpectedRollback = false;
  6. prepareForCommit(status);
  7. triggerBeforeCommit(status);
  8. triggerBeforeCompletion(status);
  9. beforeCompletionInvoked = true;
  10. // 判断是否有savePoint
  11. if (status.hasSavepoint()) {
  12. if (status.isDebug()) {
  13. logger.debug("Releasing transaction savepoint");
  14. }
  15. unexpectedRollback = status.isGlobalRollbackOnly();
  16. // 不提交,仅仅是释放savePoint
  17. status.releaseHeldSavepoint();
  18. }
  19. // 判断是否是新事务 else if (status.isNewTransaction()) {
  20. if (status.isDebug()) {
  21. logger.debug("Initiating transaction commit");
  22. }
  23. unexpectedRollback = status.isGlobalRollbackOnly();
  24. // 这里才真正去提交!
  25. doCommit(status);
  26. } else if (isFailEarlyOnGlobalRollbackOnly()) {
  27. unexpectedRollback = status.isGlobalRollbackOnly();
  28. }
  29. // Throw UnexpectedRollbackException if we have a global rollback-only
  30. // marker but still didn't get a corresponding exception from commit.
  31. if (unexpectedRollback) {
  32. throw new UnexpectedRollbackException(
  33. "Transaction silently rolled back because it has been marked as rollback-only");
  34. }
  35. }
  36. catch (UnexpectedRollbackException ex) {
  37. // can only be caused by doCommit
  38. triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
  39. throw ex;
  40. }
  41. catch (TransactionException ex) {
  42. // can only be caused by doCommit
  43. if (isRollbackOnCommitFailure()) {
  44. doRollbackOnCommitException(status, ex);
  45. } else {
  46. triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
  47. }
  48. throw ex;
  49. }
  50. catch (RuntimeException | Error ex) {
  51. if (!beforeCompletionInvoked) {
  52. triggerBeforeCompletion(status);
  53. }
  54. doRollbackOnCommitException(status, ex);
  55. throw ex;
  56. }
  57. // Trigger afterCommit callbacks, with an exception thrown there
  58. // propagated to callers but the transaction still considered as committed.
  59. try {
  60. triggerAfterCommit(status);
  61. }
  62. finally {
  63. triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
  64. }
  65. }
  66. finally {
  67. // 清空记录的资源并将挂起的资源恢复
  68. cleanupAfterCompletion(status);
  69. }
  70. }
  • 源码分析
  1. status.hasSavepoint() 如果status又savePoint,说明此时的事务是嵌套事务NESTED,这个事务外面还有事务,这里不提交,只是释放保存点。这里也可以看出来NESTED的传播行为了
  2. status.isNewTransaction() 如果是新事务才会提交!这里如果是子事务,只有PROPAGATION_NESTED状态才会走到这里提交,也说明了此状态子事务提交和外层事务是隔离的。
  3. 如果是子事务PROPAGATION_SUPPORTSPROPAGATION_REQUIREDPROPAGATION_MANDATORY这几种状态是旧事务,提交的时候将什么都不做,因为它们是运行在外层事务当中,如果子事务没有回滚,将由外层事务一次性提交

如果程序流通过了事务的层层把关,最后顺利的进入了提交流程,那么同样,Spring会将事务提交的操作引导至底层数据库连接的API,进行事务提交。

接下来看一下具体实现也就是AbstractPlatformTransactionManagerprocessCommit函数里的doCommit方法

  • 看源码(DataSourceTransactionManager.java)
  1. @Override
  2. protected void doCommit(DefaultTransactionStatus status) {
  3. DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
  4. Connection con = txObject.getConnectionHolder().getConnection();
  5. if (status.isDebug()) {
  6. logger.debug("Committing JDBC transaction on Connection [" + con + "]");
  7. }
  8. try {
  9. con.commit();
  10. }
  11. catch (SQLException ex) {
  12. throw translateException("JDBC commit", ex);
  13. }
  14. }

从回滚和提交的逻辑看,只有status是新事务,才会进行提交或回滚,需要读者记好这个状态->是否是新事务

事务的清理工作

关于清理的工作我们继续回到AbstractPlatformTransactionManagerprocessCommit函数,在这个函数里面可以看到的是无论是在异常还是没有异常的流程中,最后的finally代码块中的都会执行这个cleanupAfterCompletion(status);方法

  • 看源码(AbstractPlatformTransactionManager.java)
  1. private void cleanupAfterCompletion(DefaultTransactionStatus status) {
  2. // 设置完成状态
  3. status.setCompleted();
  4. if (status.isNewSynchronization()) {
  5. TransactionSynchronizationManager.clear();
  6. }
  7. // 如果是新事务
  8. if (status.isNewTransaction()) {
  9. doCleanupAfterCompletion(status.getTransaction());
  10. }
  11. if (status.getSuspendedResources() != null) {
  12. if (status.isDebug()) {
  13. logger.debug("Resuming suspended transaction after completion of inner transaction");
  14. }
  15. Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
  16. // 结束之前事务的挂起状态
  17. resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
  18. }
  19. }

那么如果是新事务呢,它会做哪些清除资源的操作呢?接下看一下cleanupAfterCompletion函数里的doCleanupAfterCompletion函数的具体实现:

  • 看源码(DataSourceTransactionManager.java)
  1. @Override
  2. protected void doCleanupAfterCompletion(Object transaction) {
  3. DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
  4. // Remove the connection holder from the thread, if exposed.
  5. if (txObject.isNewConnectionHolder()) {
  6. // 将数据库连接从当前线程中解除绑定,解绑过程我们在挂起的过程中已经分析过
  7. TransactionSynchronizationManager.unbindResource(obtainDataSource());
  8. }
  9. // Reset connection.
  10. // 释放连接,当前事务完成,则需要将连接释放,如果有线程池,则重置数据库连接,放回线程池
  11. Connection con = txObject.getConnectionHolder().getConnection();
  12. try {
  13. if (txObject.isMustRestoreAutoCommit()) {
  14. // 恢复数据库连接的自动提交属性
  15. con.setAutoCommit(true);
  16. }
  17. // 重置数据库连接
  18. DataSourceUtils.resetConnectionAfterTransaction(
  19. con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
  20. }
  21. catch (Throwable ex) {
  22. logger.debug("Could not reset JDBC Connection after transaction", ex);
  23. }
  24. if (txObject.isNewConnectionHolder()) {
  25. if (logger.isDebugEnabled()) {
  26. logger.debug("Releasing JDBC Connection [" + con + "] after transaction");
  27. }
  28. // 如果当前事务是独立的新创建的事务则在事务完成时释放数据库连接
  29. DataSourceUtils.releaseConnection(con, this.dataSource);
  30. }
  31. txObject.getConnectionHolder().clear();
  32. }
  • 源码分析

综上cleanupAfterCompletiondoCleanupAfterCompletion这两个方法我们可以知道的是如果在事务执行前有事务挂起,那么当前事务执行结束后需要将挂起的事务恢复。

如果有挂起的事务的话,status.getSuspendedResources()!=null为真,也就是说status中会有suspendedResource这个属性,取得status中的transaction后计入resume方法

  • 看源码(AbstractPlatformTransactionManager.java)
  1. protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
  2. throws TransactionException {
  3. if (resourcesHolder != null) {
  4. Object suspendedResources = resourcesHolder.suspendedResources;
  5. // 如果有被挂起的事务才会被进入
  6. if (suspendedResources != null) {
  7. // 真正去resume恢复的地方
  8. doResume(transaction, suspendedResources);
  9. }
  10. List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
  11. if (suspendedSynchronizations != null) {
  12. // 将上面提到的 TransactionSynchronizationManager 专门存放线程变量的类中的属性设置成被挂起事务的属性
  13. TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
  14. TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
  15. TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
  16. TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
  17. doResumeSynchronization(suspendedSynchronizations);
  18. }
  19. }
  20. }

紧接着我们再去看一下真正去resume恢复的方法doResume函数

  • 看源码(DataSourceTransactionManager.java)
  1. @Override
  2. protected void doResume(@Nullable Object transaction, Object suspendedResources) {
  3. TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
  4. }
  • 源码分析

我们可以看到 这里恢复只是把suspendedResources重新绑定到线程中。

总结

到这里之后,我们就把事务的回滚和提交就讲完了。有兴趣的童鞋可以自己再深入的了解一下。

喜欢的可以点赞关注支持一下,微信搜索【码上遇见你】及时获取更多编程知识。我们共同进步。

难道你还不知道Spring之事务的回滚和提交的原理吗,这篇文章带你走进源码级别的解读。的更多相关文章

  1. 普通的jdbc事务在插入数据后 下面的代码报错时 数据不会回滚 但是 spring的事务会回滚

    普通的jdbc事务在插入数据后 下面的代码报错时 数据不会回滚 但是 spring的事务会回滚

  2. spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)

    上一篇文章讲解了获取事务,并且通过获取的connection设置只读.隔离级别等,这篇文章讲解剩下的事务的回滚和提交 回滚处理 之前已经完成了目标方法运行前的事务准备工作,而这些准备工作最大的目的无非 ...

  3. 抛出自定义异常,spring AOP事务不回滚的解决方案

    spring AOP 默认对RuntimeException()异常或是其子类进行事务回滚,也就是说 事务回滚:throw new RuntimeException("xxxxxxxxxxx ...

  4. Spring管理事务默认回滚的异常

    一.默认方式 Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类),Error进行回滚. 如果一个方法抛出Exception或者Checked异 ...

  5. 还不懂spring中的bean的话,你一定得好好看看这篇文章

    bean的作用域 bean的生命周期 bean的装配 代码 实体类 package com; import java.util.List; public class User { private St ...

  6. spring + mybatis 注解式事务不回滚的原因分析 @Transactional

    在一个项目中发现spring的事务无法回滚. DEBUG: org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.ses ...

  7. 为什么catch了异常,但事务还是回滚了?

    前几天我发了这篇文章<我来出个题:这个事务会不会回滚?>得到了很多不错的反馈,也有不少读者通过微信.群或者邮件的方式,给了我一些关于test4的回复.其中还有直接发给我测试案例,来证明我的 ...

  8. Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  9. Spring事务异常回滚,捕获异常不抛出就不会回滚

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

随机推荐

  1. 【UE4 C++】DateTime、Timespan 相关函数

    基于UKismetMathLibrary DateTime 相关函数 Timespan 运算操作相关函数见尾部附录 /** Returns the date component of A */ UFU ...

  2. TreeSet和TreeMap中“相等”元素可能并不相等

    TreeSet和TreeMap元素之间比较大小是借助Comparator对象的compare方法. 但有些时候,即便compare()返回0也不意味着这两个元素直观上相同. 比如元素是二元组[a,b] ...

  3. Java:死锁编码及定位分析

    Java:死锁编码及定位分析 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 概念 死锁是指两个或多个以上的进程在执行过程中,因争夺资源而造成一种互相等待的现象, ...

  4. Spring Cloud Alibaba整合Sentinel

    Spring Cloud Alibaba 整合 Sentinel 一.需求 二.实现步骤 1.下载 sentinel dashboard 2.服务提供者和消费者引入sentinel依赖 3.配置控制台 ...

  5. 2021.10.7 NKOJ周赛总结

    Ⅰ. 自描述序列 问题描述: 序列 1,2,2,1,1,2,1,2,2,1,2,2,1,1,2,1,1,2,2,1,... 看似毫无规律,但若我们将相邻的数字合并 : 1,22,11,2,1,22,1 ...

  6. Exynos4412 中断处理流程详解

    Linux 中,当外设触发中断后,大体处理流程如下: a -- 具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler; b - ...

  7. Python matplotlib numpy 曼德尔布罗特集合 曼德尔布罗特 B.Madelbrot

    import numpy as np import matplotlib.pyplot as plt def mandelbrot(h,w,maxit=20): y,x = np.ogrid[-1.4 ...

  8. iostat主要性能指标

    iostat参数很多,日常运维中主要关注一下字段(根据这些字段的输出内容一般就可以确定服务器是否存在IO性能瓶颈) 1.%iowait:CPU等待输入输出完成时间的百分比.该值较高,表示磁盘存在I/O ...

  9. 这些年我@yangbodong22011参与的开源

    2020年第一天,水一篇博客,对新年起码的尊重.这里记录下我参与的开源项目情况. Talk is cheap. Show me the code Linus Torvalds Jedis PR:htt ...

  10. void * 是什么?

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它. 在哪遇到了? 线程创建函数pthread_create()的最后一个参数void *arg,嗯? ...