java - @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
...
解决方案
好吧,自动提交意味着在每条语句之后,都会提交事务并启动新的事务。插入语句不会失败,因此它会被提交。虽然更新语句失败,这就是事务被回滚并且您没有看到更改的原因。始终禁用自动提交。
推荐阅读
- apache-spark - Spark中来自关系数据模型的树/嵌套结构
- python - 查找字符串中的最后一个子字符串?
- html - 如何调整 inline-block 布局中元素之间的间距?
- r - How to select strings in a nested list from a list of indexes
- flutter - 如何将图像部分显示为颤动以获得拉幕效果?
- anaconda - 使用 python-pptx 的 ImportError
- ruby - 如何在 ruby on rails 上使用我的小课堂
- java - 清单合并失败 (AppIntro)
- python - 在抓取之前等待页面加载
- google-api - 在 Google 文档中打开图片