You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringJTA-JPA-Hibernate事务传播对数据库更新的影响及疑问

Understanding Transaction Propagation & Database Updates in Spring JTA-JPA-Hibernate

Great question! Let's break down exactly why you're seeing these two distinct behaviors—database updates when your test has no @Transactional, but no database changes when it does—by looking at how Spring manages transactions, EntityManager lifecycle, and test framework defaults.

Why Database Updates Happen When the Test Method Has No @Transactional

Your categoryService.update() method is annotated with @Transactional (default propagation level: REQUIRED). Here's what plays out when your test method doesn't have its own transaction:

  • When you call categoryService.find() first: Since this method has no @Transactional annotation, Spring creates a temporary EntityManager, runs the query, then closes the EntityManager immediately. The rootAChild1 object you get back is detached (no longer linked to an active EntityManager/transaction).
  • After modifying the detached object's name, you call categoryService.update(): Spring detects there's no active transaction, so it creates a new one and binds a fresh EntityManager to it. The em.merge(category) call takes your detached object, copies its state into a new managed instance in the current EntityManager's context, and marks it for persistence.
  • When update() finishes executing, Spring automatically commits this new transaction. Hibernate flushes the managed object's changes to the database, so you see the update in your database.
  • The subsequent categoryService.find() call creates another temporary EntityManager, pulls the fresh updated data from the database, and your assertions pass.

Why No Database Updates Happen When the Test Method Has @Transactional

This boils down to Spring Test's default transaction rollback behavior:
Any test method annotated with @Transactional will automatically have its transaction rolled back when the test finishes. This is a built-in feature to prevent test data from polluting your database across test runs.

Let's break down each propagation level you tested:

  • REQUIRED: Your categoryService.update() joins the existing test method transaction. All changes (including the merge call) are tracked in the test's EntityManager and its first-level cache. But when the test ends, the entire transaction is rolled back—so none of those changes make it to the database. The first-level cache still has the modified object, which is why your find() call returns the updated name.
  • REQUIRES_NEW: Even though this propagation level creates a separate transaction context, if you've set it on the test method itself, it's still the test's transaction that gets rolled back. Only if you applied REQUIRES_NEW to the update() method would that sub-transaction commit independently. Since your test method owns the transaction, all operations within it are rolled back.
  • NESTED: Nested transactions are tightly tied to the parent test transaction. When the parent rolls back, all nested transactions roll back too—so no changes persist to the database. The first-level cache retains the modified object during the test execution, hence your local assertions pass.

If you want to see database updates when using @Transactional in your test, add the @Rollback(false) annotation to your test method. This disables the automatic rollback and lets the transaction commit normally.


内容的提问来源于stack exchange,提问作者Geek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:09:43