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

Java EE不同Bean间事务类型差异及问题咨询

Great question—this gets into the nuanced differences between CDI beans and EJBs when it comes to transaction management, which is a common point of confusion. Let’s break this down step by step.

1. Core Difference: CDI Beans vs. EJBs in Transaction Handling

  • Unannotated CDI Beans (like your original ClassThree): These don’t have container-managed transactions (CMT) by default. When an EJB (like ClassTwo) calls a method on a CDI bean, the CDI bean runs within the caller’s transaction context, but the container doesn’t treat exceptions from the CDI bean as trigger points for transaction rollback. The exception is just a regular Java exception—your catch block in ClassTwo can handle it, rethrow it, etc., and the transaction only gets marked for rollback if the EJB itself throws an unhandled unchecked exception (or you explicitly mark it with setRollbackOnly()).

  • EJB Beans (like your modified @Stateless ClassThree): EJBs use CMT by default, with the REQUIRED transaction attribute. This means:

    • When called from another EJB (ClassTwo), it joins the existing transaction context.
    • If an EJB throws an unchecked exception (like RuntimeException), the EJB container automatically marks the transaction for rollback and wraps the exception in an EjbTransactionRolledBackException (a subclass of EjbException). Even if you catch the exception in ClassTwo, the transaction is already marked as rollback-only—so when ClassTwo’s method completes, the transaction rolls back, which breaks ClassOne’s persistence logic.

2. Why Your Transaction Attribute Tests Behaved the Way They Did

Let’s go through each attribute you tested:

  • SUPPORTS/REQUIRED: Both join the existing transaction from ClassTwo. When ClassThree throws RuntimeException, the container marks the shared transaction as rollback-only. Your catch block in ClassTwo can’t undo this—so the transaction rolls back when it propagates back to ClassOne.
  • NOT_SUPPORTED: This tells the container to suspend the caller’s transaction before executing ClassThree’s method. Since your methodInClassThree uses JpaRepository, which requires an active transaction for write operations, you get TransactionRequiredException immediately—JPA can’t work without a transaction here.
  • REQUIRES_NEW: This creates a brand new, independent transaction for ClassThree’s method. When the RuntimeException is thrown, only this new transaction rolls back. The original transaction from ClassTwo/ClassOne remains intact, so ClassOne’s persistence logic works just like it did with the CDI bean version.

3. Why the Default Behavior Seems Counterintuitive

You’re right that EJBs default to REQUIRED, but the key difference is that EJBs have container-managed exception handling that CDI beans don’t. With the CDI bean, the exception is just a regular Java exception—you control whether it propagates and affects the transaction. With the EJB, the container intercepts unchecked exceptions and automatically marks the transaction for rollback, regardless of whether you catch it in the caller.

4. Key Takeaways

  • CDI beans rely on the caller’s transaction context but don’t trigger container-level transaction rollback from exceptions.
  • EJBs with CMT automatically handle transaction rollback for unchecked exceptions, even if the caller catches the exception.
  • Use REQUIRES_NEW if you want an EJB’s exception to be isolated from the caller’s transaction (matching your original CDI bean behavior).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:40:45