首页 > 解决方案 > @Transactional 回滚 session.save() 异常

问题描述

我一直在使用@Transactional注释测试回滚。如果抛出未经检查的异常,session则应回滚操作。

我正在使用org.hibernate.dialect.Oracle12cDialect.

我已@EnableTransactionManagement启用。

在第一个示例entity中,数据库中已经存在。我正在将它的名称从“Test”更新为“Test123”。session.saveOrUpdate()调用后,RuntimeException抛出 a。事后检查数据库,更新没有通过。

@RequestMapping("/test")
@RestController
@Transactional
public class TestController {

    @Autowired
    protected SessionFactory sessionFactory;

    @RequestMapping(value = "")
    public String test() {
        
        Session session = sessionFactory.getCurrentSession();

        MyEntity entity = new MyEntity();
        entity.setId(123); // Update existing
        entity.setName("Test123");
        entity.setCreateUser("user1");
        entity.setUpdateUser("user1");

        session.saveOrUpdate(entity);

        throw new RuntimeException("Test");
    }
}

在第二个示例entity中,数据库中尚不存在。调用session.saveOrUpdate()a后RuntimeException()再次抛出。检查数据库时,创建了新记录。

@RequestMapping("/test")
@RestController
@Transactional
public class TestController {

    @Autowired
    protected SessionFactory sessionFactory;

    @RequestMapping(value = "")
    public String test() {
        
        Session session = sessionFactory.getCurrentSession();

        MyEntity entity = new MyEntity();
        entity.setId(null); // Create new 
        entity.setName("TestNew");
        entity.setCreateUser("user1");
        entity.setUpdateUser("user1");

        session.saveOrUpdate(entity);

        throw new RuntimeException("Test");
    }
}

我发现一个有趣的事情是,在第一个示例中,hibernate 不会在控制台中打印出任何 SQL。但是,在第二个示例中,插入语句在抛出异常之前在控制台中打印。这有什么不同吗?

在最后一个示例中,我将我的语句包装在手动事务中。类似于第二个例子,entity在数据库中不存在。我们正在创建一个新实例。在事务中,我抛出一个RuntimeException() 异常被捕获并且事务成功回滚。新记录不在数据库中。

@RequestMapping("/test")
@RestController
@Transactional
public class TestController {

    @Autowired
    protected SessionFactory sessionFactory;

    @RequestMapping(value = "")
    public String test() {
        
        Session session = sessionFactory.getCurrentSession();

        Transaction tx = null;

        try {
            tx = session.beginTransaction();

            MyEntity entity = new MyEntity();
            entity.setId(null); // Create new 
            entity.setName("TestNew2");
            entity.setCreateUser("user1");
            entity.setUpdateUser("user1");

            session.saveOrUpdate(entity);

            throw new RuntimeException("Test");
            
            tx.commit();
            
        } catch(Exception e) {
            if (tx != null) {
                tx.rollback();
            }
        }
    }
}

为什么示例二不回滚?但是示例三确实成功回滚了吗?

编辑:我也在使用 Hikari CP。已auto-commit设置为true. 我不确定这是否会影响任何事情。但是当我将它设置为 时false,我至少看不到数据库中的变化。但我相信那是因为那时我需要进行手动交易。

这里还有日志,以防有任何有用的地方:

2021-02-21 10:44:42.604 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2021-02-21 10:44:42.650 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder@68d89998] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@367628c8] to thread [http-nio-8081-exec-1]
2021-02-21 10:44:42.659 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@68d89998] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@367628c8] bound to thread [http-nio-8081-exec-1]
2021-02-21 10:44:42.659 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@393e2dcf] for JPA transaction
2021-02-21 10:44:42.659 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Creating new transaction with name [com.package.myentity.web.PingService.createOrUpdate]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2021-02-21 10:44:42.709 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@77af7c9c]
2021-02-21 10:44:42.709 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder@77b95111] for key [HikariDataSource (My WS)] to thread [http-nio-8081-exec-1]
2021-02-21 10:44:42.709 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2021-02-21 10:44:42.710 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.t.i.TransactionInterceptor           : Getting transaction for [com.package.myentity.web.PingService.createOrUpdate]
2021-02-21 10:44:42.713 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.hibernate5.SessionHolder@4a056888] for key [org.hibernate.internal.SessionFactoryImpl@4639d92c] to thread [http-nio-8081-exec-1]
2021-02-21 10:36:25.781 DEBUG VT0718LA899 --- [nio-8081-exec-2] o.h.SQL                                  : 
    insert 
    into
        dev_schema.my_entity
        (id, name, create_user, update_user) 
    values
        (?, ?, ?, ?)
44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.t.i.TransactionInterceptor           : Completing transaction for [com.package.myentity.web.PingService.createOrUpdate] after exception: java.lang.RuntimeException
2021-02-21 10:44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.t.i.RuleBasedTransactionAttribute    : Applying rules to determine whether transaction should rollback on java.lang.RuntimeException
2021-02-21 10:44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.t.i.RuleBasedTransactionAttribute    : Winning rollback rule is: null
2021-02-21 10:44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.t.i.RuleBasedTransactionAttribute    : No relevant rollback rule found: applying default rules
2021-02-21 10:44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Triggering beforeCompletion synchronization
2021-02-21 10:44:42.935 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.hibernate5.SessionHolder@4a056888] for key [org.hibernate.internal.SessionFactoryImpl@4639d92c] from thread [http-nio-8081-exec-1]
2021-02-21 10:44:42.935 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Initiating transaction rollback
2021-02-21 10:44:42.935 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Rolling back JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@393e2dcf]
2021-02-21 10:44:42.986 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2021-02-21 10:44:42.986 TRACE VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Triggering afterCompletion synchronization
2021-02-21 10:44:42.988 TRACE VT0718LA899 --- [nio-8081-exec-1] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder@77b95111] for key [HikariDataSource (My WS)] from thread [http-nio-8081-exec-1]
2021-02-21 10:44:42.988 DEBUG VT0718LA899 --- [nio-8081-exec-1] o.s.o.j.JpaTransactionManager            : Not closing pre-bound JPA EntityManager after transaction
java.lang.RuntimeException

...

标签: javaspringhibernateoracle12c

解决方案


好吧,自动提交意味着在每条语句之后,都会提交事务并启动新的事务。插入语句不会失败,因此它会被提交。虽然更新语句失败,这就是事务被回滚并且您没有看到更改的原因。始终禁用自动提交。


推荐阅读