【发布时间】:2013-07-10 10:51:01
【问题描述】:
总结:
有人决定 EntityExistsException 是 RuntimeException 以避免强迫开发人员捕获异常。避免这种异常回滚事务的方法是什么?如果您捕获 EntityExistsException,则该事务已被容器回滚...恕我直言 EntityExistsException 并不是真正的运行时异常...应该可以从此类异常中恢复...如何捕获运行时异常和重新抛出应用程序异常(选中)。它在 2 个无状态会话 bean 中进行了测试。
详细说明:
在我的示例中,我有 2 个无状态会话 bean。
第一个会话 bean 将启动一个新事务 (REQUIRES_NEW) bean 将保留一个新实体。 然后调用第二个无状态会话 bean。
第二个会话 bean 没有启动新事务(MANDATORY 或 REQUIRED),因为它是由启动事务的 bean 调用的 第二个会话 bean 将第二次保留同一实体。 JPA 抛出 javax.persistence.EntityExistsException 但实际抛出的是 javax.ejb.EJBTransactionRolledbackException。 (这只是一个例子,恕我直言,任何会抛出 RuntimeException 的方法都会回滚事务。我找到了一种人为产生实体存在异常的方法......)
我创建了一个 ApplicationException。我们知道默认情况下 ApplicationException 不会回滚事务。
在第二个 ejb 中,我捕获了 EJBTransactionRolledbackException(或 EntityExistsException) 我抛出了一个应用程序异常。事务不应回滚!
第二个 bean 加入了事务,它对事务有影响,因为事务总是回滚。
有没有办法避免该事务由于 RuntimeException (EntityExistsException) 而回滚?我捕获了 EntityExistsException 或 EJBTransactionRolledbackException 并重新抛出应用程序异常。
恕我直言,如果第二个事务还需要一个新事务 (REQUIRES_NEW),则可以避免这种情况。但我想避免这种情况,只保留一笔交易...... 你能帮帮我吗?
从 openejb 记录:
第一个会话 bean 和第一个方法
DEBUG 10-07 12:20:53,002 (Log4jLogStream.java:debug:81) -TX NotSupported: 没有要挂起的事务 DEBUG 10-07 12:20:53,002 (Log4jLogStream.java:debug:81) -TX RequiresNew:没有事务暂停 调试 10-07 12:20:53,003 (Log4jLogStream.java:debug:81) -TX RequiresNew: 开始事务 org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f 1 坚持1睡10后
第二个会话 bean 和第二个方法
DEBUG 10-07 12:21:03,009 (Log4jLogStream.java:debug:81) - 在 bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001 上调用方法创建 DEBUG 10-07 12:21:03,011 (Log4jLogStream.java:debug:81) - 完成调用方法创建。返回值:proxy=be.awl.clearing.bcmc.core.utils.TestService001;deployment=bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001;pk=null DEBUG 10-07 12:21:03,012 (Log4jLogStream.java:debug:81) - 在 bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001 上调用方法 writeToDatabase,标识为 null 调试 10-07 12:21:03,014 (Log4jLogStream.java:debug:81) -TX NotSupported: 暂停事务 org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f 调试 10-07 12:21:03,014 (Log4jLogStream.java:debug:81) -TX NotSupported: 恢复事务 org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f 只得到回滚假 2
DEBUG 10-07 12:21:03,018 (Log4jLogStream.java:debug:85) - bean 实例业务方法遇到系统异常:具有相同标识符值的不同对象已与会话关联:[be. awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model。参数.RepBcmcParamId@aed63ef8] ...
DEBUG 10-07 12:21:03,020 (Log4jLogStream.java:debug:81) - 完成调用 writeToDatabase 方法并出现异常 org.apache.openejb.core.transaction.TransactionRolledbackException:事务已被标记为回滚,只是因为 bean遇到非应用程序异常:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing .bcmc.core.model.parameters.RepBcmcParamId@aed63ef8]
DEBUG 10-07 12:21:03,021 (Log4jLogStream.java:debug:85) - bean 实例业务方法遇到系统异常:事务被标记回滚只是因为 bean 遇到了非应用程序异常 :javax .persistence.EntityExistsException :具有相同标识符值的不同对象已与会话关联:[be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters .RepBcmcParamId@aed63ef8] javax.ejb.EJBTransactionRolledbackException:事务被标记回滚只是因为 bean 遇到了非应用程序异常:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing .bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ... 原因:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core .model.parameters.RepBcmcParamId@aed63ef8] ...
DEBUG 10-07 12:21:03,022 (Log4jLogStream.java:debug:81) -TX RequiresNew:回滚事务 org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f
DEBUG 10-07 12:21:03,024 (Log4jLogStream.java:debug:81) -TX RequiresNew:没有要恢复的事务
DEBUG 10-07 12:21:03,024 (Log4jLogStream.java:debug:81) - 完成调用 writeToDatabase 方法并出现异常 java.rmi.RemoteException:bean 遇到非应用程序异常;嵌套异常是: javax.ejb.EJBTransactionRolledbackException:事务被标记回滚只是因为 bean 遇到了非应用程序异常:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing .bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] 线程“Thread-49”中的异常 javax.ejb.EJBException:bean 遇到了非应用程序异常;嵌套异常是: javax.ejb.EJBTransactionRolledbackException:事务被标记回滚只是因为 bean 遇到了非应用程序异常:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing .bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ... 原因:javax.ejb.EJBTransactionRolledbackException:事务被标记为回滚只是因为 bean 遇到了非应用程序异常:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已经与会话相关联:[be. awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ... 原因:javax.persistence.EntityExistsException:具有相同标识符值的不同对象已与会话关联:[be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core .model.parameters.RepBcmcParamId@aed63ef8] ...
第一个会话 bean:
@Stateless(name = "bcmc-core.be.awl.clearing.bcmc.core.utils.TestService")
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class TestServiceImpl implements TestService {
@PersistenceContext(unitName = "bcmc-core")
private EntityManager em;
@Override
public void writeToDatabase() {
try {
RepBcmcParam bcmcParam = new RepBcmcParam();
RepBcmcParamId bcmcParamId = new RepBcmcParamId();
bcmcParamId.setProcname("procname");
bcmcParamId.setParid("parid");
Date date = new Date();
bcmcParamId.setDtbeg(date);
bcmcParam.setId(bcmcParamId);
bcmcParam.setParval("parval");
System.out.println("1");
em.persist(bcmcParam);
System.out.println("after persist 1 sleeping 10");
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
TestService001 testService001 = net.atos.xa.resourcelocator.ResourceLocator.lookup(TestService001.class);
testService001.writeToDatabase(date);
System.out.println("after write to database 2 sleeping 10");
try {
Thread.currentThread().sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch(BcmcDuplicateException be) {
System.out.println("facade");
}
}
第二个会话 bean:
@Stateless(name = "bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001")
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class TestService001Impl implements TestService001 {
@PersistenceContext(unitName = "bcmc-core")
private EntityManager em;
private static final Logger LOGGER = Logger.getLogger(Constants.APP_NAME);
@Resource
private SessionContext context;
try {
System.out.println("get rollback only " + context.getRollbackOnly());
RepBcmcParam bcmcParam = new RepBcmcParam();
RepBcmcParamId bcmcParamId = new RepBcmcParamId();
bcmcParamId.setProcname("procname");
bcmcParamId.setParid("parid");
bcmcParamId.setDtbeg(date);
//bcmcParamId.setDtbeg(new Date());
bcmcParam.setId(bcmcParamId);
bcmcParam.setParval("parval");
System.out.println("2");
em.persist(bcmcParam);
System.out.println("get rollback only " + context.getRollbackOnly());
try {
System.out.println("1 sec");
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch(EJBTransactionRolledbackException e) {
System.out.println("get rollback only " + context.getRollbackOnly());
throw new BcmcDuplicateException();
}
}
【问题讨论】: