【问题标题】:Java EE @TransactionManagement.BEAN - how does it combine with container managed beans?Java EE @TransactionManagement.BEAN - 它如何与容器管理的 bean 结合使用?
【发布时间】:2013-01-04 09:12:33
【问题描述】:

在 callSessionBean2() 中启动的事务在以下场景中将如何表现?是否暂停?如果在 SessionBean2 中抛出异常会发生什么? SessionBean2 设置为 BEAN 事务管理类型,因为它不与任何数据库通信,仅通过 LDAP 与 AD 服务器通信。

我之所以这么问,是因为在部署后几周我在生产服务器中遇到问题,对 SessionBean2 的调用开始挂起,唯一的错误是事务超时。我认为这个设置可能是一件坏事,有人能解释一下吗?

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class SessionBean1 {
    @Inject private SessionBean2 sessionBean2;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void callSessionBean2(){
        sessionBean2.doThingsThatMightCauseException();
    }
}

@Singleton
@TransactionManagement(TransactionManagementType.BEAN)
public class SessionBean2 {
    public void doThingsThatMightCauseException(){...}
}

【问题讨论】:

    标签: transactions java-ee-6 session-bean


    【解决方案1】:

    正如 EJB 3.1 规范 (§13.6.1) 中所声明的,调用者的事务将被暂停:

    如果客户端请求与事务 T1 相关联,并且 实例未与事务关联,容器挂起 客户端的事务关联并使用 未指定的事务上下文。容器恢复客户端的 事务关联(T1)当方法(连同任何 相关的拦截器方法)完成。

    因此,与SessionBean1 关联的事务被挂起,SessionBean2 在任何一种情况下抛出的异常都将由调用 bean 处理,并具有适当的语义(即由 CMT 会话处理)

    您的代码是正确的,但我宁愿使用:

    @TransactionManagement(TransactionManagementType.CONTAINER)
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public class SessionBean2 {
        public void doThingsThatMightCauseException(){...}
    }
    

    同样的效果。

    您遇到的问题可能与@Singleton 注解有关,它 根据 §4.8.5.3 和 §4.8.5.3 默认 bean 为:

    @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
    @Lock(LockType.WRITE)
    

    这会序列化doThingsThatMightCauseException 的调用,从而导致随机的ConcurrentAccessTimeoutException。虽然可以通过@AccessTimeout 配置并发访问超时,但如果(序列化)doThingsThatMightCauseException 访问延迟超过为 CMT 事务定义的超时(请记住,与 SessionBean1 关联的 CMT 事务被挂起,则会导致事务超时,但时钟仍在计数......)。

    总结一下:

    您需要(适当注意共享状态)更改doThingsThatMightCauseException 上的访问锁:

    @Lock(LockType.READ)
    public void doThingsThatMightCauseException(){...}
    

    这将删除访问序列化,希望能解决您的超时问题。

    如果您仍然遇到超时,这将与 doThingsThatMightCauseException 中包含的操作的缓慢有关。 在这种情况下,您需要:

    • 在任何事务之外调用该方法,
    • 或更改 CMT 事务超时(在 AS 特定配置/部署中)
    • 或将SessionBean1 转换为BMT,从而利用UserTransaction.setTransactionTimeout

    【讨论】:

    • 感谢您的信息,我正在使用单例,因为我在其中有一个 LDAP 连接池,但我可能会尝试切换到无状态 bean 并让它们每个都有自己的连接。我认为真正的问题是 LDAP 连接似乎挂了很长时间,导致事务超时,并且还阻止其他进程使用该服务,从而破坏了整个应用程序。
    • LDAP 池永远不会对@Lock(LockType.WRITE) 有用,它将始终使用单个连接...@Lock(LockType.READ) 应该解决它
    【解决方案2】:

    我的建议是手动管理所有交易。 根据Java 6 EE specification

    使用容器管理的事务划分的企业 bean 不得使用任何会干扰的事务管理方法 容器的事务分界边界。这样的例子 方法是 commit、setAutoCommit 和 rollback 方法 java.sql.Connection 或提交和回滚方法 javax.jms.Session。如果您需要控制交易 划界,您必须使用应用程序管理的事务划界。

    使用容器管理的事务划分的企业 bean 也不能使用 javax.transaction.UserTransaction 接口。

    【讨论】:

    • 我没有破坏该引用中的建议,我没有在 SessionBean2 中使用任何与事务相关的方法。与其手动管理所有内容,我可能更愿意将 SesisonBean2 设置为容器管理对性能的轻微影响
    • 我错过了,我以为你在第二个 bean 中做了一些与事务相关的处理。在这种情况下,调用方法的行为取决于您在被调用方法中抛出的异常类型。见Rolling Back a Container-Managed Transaction。如果您想在每种类型的异常上回滚事务,您可以在 callSessionBean2 方法中捕获它们并调用 setRollbackOnly
    猜你喜欢
    • 2015-06-23
    • 1970-01-01
    • 2013-06-15
    • 2014-04-30
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多