Java 正在捕获EJBTransactionRolledbackException

Java 正在捕获EJBTransactionRolledbackException,java,jakarta-ee,ejb,Java,Jakarta Ee,Ejb,我无法理解EJBTransactionRolledbackException 我有一个实体: @Entity public class MyEntity { @Id @GeneratedValue private Long id; @Size(max=5) private String name; //... } 以及由于易于CMT而成为SLSB的存储库: @Stateless public class ExampleRepository {

我无法理解EJBTransactionRolledbackException

我有一个实体:

@Entity
public class MyEntity {

    @Id
    @GeneratedValue
    private Long id;
    @Size(max=5)
    private String name;
//...
}
以及由于易于CMT而成为SLSB的存储库:

@Stateless
public class ExampleRepository {
    @PersistenceContext
    private EntityManager em;

    public void add(MyEntity me) {
        em.persist(me);
    }
}
现在我有了测试Servlet,当我模拟ConstraintViolation(名称太长)时

我知道在这种情况下,EJB容器将包装ConstraintViolationException,因此我将捕获EJBTransactionRolledbackException。问题是,在控制台中,我可以从catch块(“Exception catch”)中看到我的消息,但在此之前,会生成大量异常日志()。
我不太明白发生了什么-这个异常是否被捕获?在这种简单的情况下,如何防止控制台中出现所有这些错误消息?

我可以向您推荐两种解决方案:

  • 使用bean管理的事务:

    @Stateless
    @TransactionManagement(TransactionManagementType.BEAN)
    public class ExampleRepository {
        @PersistenceContext(synchronization = SynchronizationType.UNSYNCHRONIZED))
        private EntityManager em;
    
        @Resource
        private UserTransaction tx;
    
        public void add(MyEntity me) {
            try {
                tx.begin();
                em.joinTransaction();
                em.persist(me);
                tx.commit();
            } catch (ValidationException ex) {
                throw new AppValidationException(ex);
            }
        }
    }
    
  • 委托/外观模式:

    您将示例存储库保持原样:

    @Stateless
    public class ExampleRepository {
        @PersistenceContext
        private EntityManager em;
    
        public void add(MyEntity me) {
            em.persist(me);
        }
    }
    
    创建不带事务的新EJB(使用与initial相同的方法):

    在servlet中使用新的委托bean:

    @WebServlet("/example")
    public class ExampleServlet extends HttpServlet {
        @Inject
        private ExampleRepositoryDelegate repoDelegate;
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            MyEntity me = new MyEntity();
            me.setName("TooLongName");
            try {
                repoDelegate.add(me);
            } catch(Exception e) {
                System.out.println("Exception caught");
            }
        }
    }
    

  • 我可以向您推荐两种解决方案:

  • 使用bean管理的事务:

    @Stateless
    @TransactionManagement(TransactionManagementType.BEAN)
    public class ExampleRepository {
        @PersistenceContext(synchronization = SynchronizationType.UNSYNCHRONIZED))
        private EntityManager em;
    
        @Resource
        private UserTransaction tx;
    
        public void add(MyEntity me) {
            try {
                tx.begin();
                em.joinTransaction();
                em.persist(me);
                tx.commit();
            } catch (ValidationException ex) {
                throw new AppValidationException(ex);
            }
        }
    }
    
  • 委托/外观模式:

    您将示例存储库保持原样:

    @Stateless
    public class ExampleRepository {
        @PersistenceContext
        private EntityManager em;
    
        public void add(MyEntity me) {
            em.persist(me);
        }
    }
    
    创建不带事务的新EJB(使用与initial相同的方法):

    在servlet中使用新的委托bean:

    @WebServlet("/example")
    public class ExampleServlet extends HttpServlet {
        @Inject
        private ExampleRepositoryDelegate repoDelegate;
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            MyEntity me = new MyEntity();
            me.setName("TooLongName");
            try {
                repoDelegate.add(me);
            } catch(Exception e) {
                System.out.println("Exception caught");
            }
        }
    }
    

  • 请看下面的解释:

    您必须理解,处理异常和处理事务是同时发生的两件不同的事情系统异常无条件触发事务回滚。当您看到一个
    ConstraintViolationException
    ,它是一个系统异常,因为它扩展了
    RuntimeException
    ,它不仅仅是包装和重新抛出。在此过程中发生了一件坏事-您的事务已中止

    因此,回答第一个问题,如果异常(
    ConstraintViolationException
    )被捕获-是的,它被容器捕获。事务被中止,并引发一个新的异常以通知应用程序代码


    您可以禁止记录这些消息,但这样您就不会知道数据持久性故障。

    请查看以下说明:

    您必须理解,处理异常和处理事务是同时发生的两件不同的事情系统异常无条件触发事务回滚。当您看到一个
    ConstraintViolationException
    ,它是一个系统异常,因为它扩展了
    RuntimeException
    ,它不仅仅是包装和重新抛出。在此过程中发生了一件坏事-您的事务已中止

    因此,回答第一个问题,如果异常(
    ConstraintViolationException
    )被捕获-是的,它被容器捕获。事务被中止,并引发一个新的异常以通知应用程序代码


    您可以禁止记录这些消息,但这样您就不会知道数据持久性失败。

    事实上,我知道可能的解决方案,但我不明白为什么我的场景中会出现异常,但是控制台显示了太多的日志,所以看起来好像不是因为日志中的消息是由容器(事务协调器组件)编写的。查看:WARN ARJUNA012125:TwoPhaseCoordinator.beforeCompletion-同步执行失败。Container报告它捕获了一个系统异常并中止了事务。事实上,我知道可能的解决方案,但我不明白为什么我的场景中的异常似乎被捕获,但console显示了如此多的日志,因此它看起来好像没有被捕获。日志中的消息是由容器写入的,事务协调器组件
    arjuna
    。查看:WARN ARJUNA012125:TwoPhaseCoordinator.beforeCompletion-同步执行失败。容器报告它已捕获系统异常并中止事务。