摘要:
有人认为EntityExistsException是一个RuntimeException,以避免强制开发人员捕获异常。什么是避免此异常回滚事务的方法?如果捕获到EntityExistsException,则事务已经被容器回滚... imho EntityExistsException实际上不是运行时异常......应该可以从这样的异常中恢复...如何捕获运行时异常和重新抛出应用程序异常(已选中)。它在2个无状态会话bean中进行了测试。
详情:
在我的例子中,我有2个无状态会话bean。
第一个会话bean将启动一个新事务(REQUIRES_NEW) bean将持久保存新实体。 然后调用第二个无状态会话bean。
第二个会话bean没有启动新事务(MANDATORY或REQUIRED),因为它是由启动事务的bean调用的 第二个会话bean将第二次持久存在于同一实体中。 JPA抛出javax.persistence.EntityExistsException,但实际抛出的是javax.ejb.EJBTransactionRolledbackException。 (这只是一个例子,imho任何抛出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:暂停没有事务 DEBUG 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)-invoking method on 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)-boking_bm.c. DEBUG 10-07 12:21:03,014(Log4jLogStream.java:debug:81)-TX NotSupported:暂停的事务org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f DEBUG 10-07 12:21:03,014(Log4jLogStream.java:debug:81)-TX NotSupported:恢复事务org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f 获取回滚仅为false 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。 parameters.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] 线程中的异常"线程-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();
}
}
答案 0 :(得分:1)
客户端无法捕获系统异常(非@ExpressException RuntimeException)并在事务回滚之前将其转换为应用程序异常。唯一的选择是以某种方式调整EJB:将其更改为首先抛出应用程序异常,添加执行catch / rethrow的拦截器,或将系统异常更改为应用程序异常(通过注释或XML) )。
答案 1 :(得分:0)
在这里退后一步....为什么你想要第二个bean在第一个bean已经存在的情况下持久保存相同的对象..在同一个事务中也是如此?也许你应该在弄乱容器处理这个异常的方式之前重新考虑原始解决方案?
回到你的问题,你的Application异常是否是一个RuntimeException的子类?另外,如果你必须这样做,你可以在这个例外情况下手动提交交易吗?