Spring事务:意外的回滚行为

时间:2018-06-13 14:15:48

标签: spring spring-jdbc spring-transactions jdbctemplate

我正在进行一个简单的实验以进行调试。

首先我将几条记录插入到数据库中,然后我执行无效的数据转换,这会引发DataIntegrityViolationException,但我会捕获异常。

我希望记录成功插入到db中,因为我捕获了已检查的异常。但是整个事情都被推回了。

我再次使用TransactionTemplate进行实验,而不是使用注释,结果相同。

我的问题是:

  1. 这是预期的行为吗?
  2. 如果1号的回答是肯定的,那么我会抓住异常,春天怎么可能知道抛出了异常?
  3. 这是我的代码:

    public void insertValue() {
        jdbcTemplate.execute("insert into people (person_id, name) values (4, 'asjkdhadsjkqhweqkewhkashdkahd')");
        jdbcTemplate.execute("insert into people (person_id, name) values (5, 'tttqqq')");
    }
    // this should throw exception
    public void truncateValue() {
        jdbcTemplate.execute("alter table people alter column name varchar(7)");
    }
    
    public void jdbc_calls() {
        insertValue();
        try {
            truncateValue();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("Finish");
    }
    
    public void run() {
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
    
        transactionTemplate.execute(transactionStatus -> {
            try {
                jdbc_calls();
            } catch (RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
            return null;
        });
    }
    

    关于问题2的更多信息。 这是TransactionTemplate.execute()的源代码 根据我的理解,如果我不抛出异常,则会触发rollbackOnException。

    public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
    
        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 | Error ex) {
                // Transactional code threw application exception -> rollback
                rollbackOnException(status, ex);
                throw ex;
            }
            catch (Throwable ex) {
                // Transactional code threw unexpected exception -> rollback
                rollbackOnException(status, ex);
                throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
            }
            this.transactionManager.commit(status);
            return result;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

  
      
  1. 这是预期的行为吗?
  2.   

是的,是的。

  
      
  1. 如果1号的回答是肯定的,那么我会抓住异常,春天怎么可能知道抛出了异常?
  2.   

发生异常时,spring会将您的交易标记为rollbackOnly。 因此,即使您捕获异常,在方法结束时,您的事务仍会回滚。

在您的情况下,我不知道您使用@Transaction的原因,因为无论是否发生异常都要提交。

修改

当您使用DB事务时,事务调用将委托给EntityManager。

查看AbstractEntityManagerImpl#handlePersistenceException

@Override
public void handlePersistenceException(PersistenceException e) {
    if ( e instanceof NoResultException ) {
        return;
    }
    if ( e instanceof NonUniqueResultException ) {
        return;
    }
    if ( e instanceof LockTimeoutException ) {
        return;
    }
    if ( e instanceof QueryTimeoutException ) {
        return;
    }

    try {
        markForRollbackOnly();
    }
    catch ( Exception ne ) {
        //we do not want the subsequent exception to swallow the original one
        LOG.unableToMarkForRollbackOnPersistenceException(ne);
    }
}

当发生异常时,EntityManager会将您的事务标记为rollbackOnly,然后抛出异常以便捕获。

在您的服务中捕获异常后,AbstractPlatformTransactionManager将尝试提交(因为,如您所知,没有检测到异常),但EntityManager拒绝提交,因为它检测到事务标记为只回滚。

如果你阅读了例外,你会看到类似的内容:

  

javax.persistence.RollbackException:标记为rollbackOnly的事务