我对理解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(名字太长)时。
@WebServlet("/example")
public class ExampleServlet extends HttpServlet {
@Inject
private ExampleRepository repo;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyEntity me = new MyEntity();
me.setName("TooLongName");
try {
repo.add(me);
} catch(EJBTransactionRolledbackException e) {
System.out.println("Exception caught");
}
}
}
我知道在这种情况下,EJB容器会包装ConstraintViolationException,因此我会捕获EJBTransactionRolledbackException。问题是在控制台中我可以看到来自catch块的消息(“异常捕获”)但在此之前产生了大量的异常日志(link)。 我不太明白发生了什么 - 这个例外是否被捕获?如何在如此简单的场景中阻止控制台中的所有这些错误消息?
答案 0 :(得分:2)
请查看以下解释:A clear explanation of system exception vs application exception
您必须了解处理异常和处理事务是两个不同的事情发生在一起。 系统异常无条件触发事务回滚。当您看到ConstraintViolationException
,这是一个系统异常,因为它扩展了RuntimeException
,它不仅仅是包装和重新投掷。在此过程中发生了一件坏事 - 您的交易已经中止。
所以,回答第一个问题,如果异常(ConstraintViolationException
)被捕获 - 是的,它被容器捕获了。事务中止并抛出一个新的异常以通知应用程序代码。
您可以禁止记录这些消息,但是您不会知道数据持久性失败。
答案 1 :(得分:0)
我可以建议你两个解决方案:
使用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);
}
}
}
委托/门面模式:
按原样保留 ExampleRepository :
@Stateless
public class ExampleRepository {
@PersistenceContext
private EntityManager em;
public void add(MyEntity me) {
em.persist(me);
}
}
创建没有事务的新EJB(使用与初始相同的方法):
@Stateless
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class ExampleRepositoryDelegate {
@EJB
private ExampleRepository repository;
public void add(MyEntity me) {
try {
repository.add(me);
} catch (ValidationException e) {
e.printStackTrace();
}
}
}
在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");
}
}
}