我有 EJB 2.0 遗留代码。它有一个 session bean:
/**
* @ejb.bean
* name="Sample"
* type="Stateless"
* view-type="both"
* @ejb.transaction
* type="Required"
* @ejb.util
* generate="physical"
*/
public abstract class SampleEJB
implements SessionBean {
public void delete(Long id) {
EJBLocalObject local_o = getEjbLocalObject(id);
invokeDelete(local_o);
}
private void invokeDelete(EJBLocalObject local_o)
throws Exception
{
try
{
...
EJBLocalObject local_another_o = getEjbLocalObject(local_o.getAnotherId());
local_another_o.remove();
...
}
catch (Exception e)
{
// log exception
// throw new exception
}
try
{
...
local_o.remove();
...
}
catch (Exception e)
{
// log exception
// throw new exception
}
}
有时由于数据库问题,第一次删除调用会成功。但第二次删除调用失败并抛出异常。
这会导致数据库不一致。要求是,所有删除调用都应该成功。如果其中一个调用失败,它应该回滚之前的删除。如何处理这种情况?
对于 BMT,我们可以划分事务的启动、提交和回滚。但它是CMT,所以我不确定在EJB2.0中如何处理这种情况。请让我知道可以做什么。
最佳答案
@ejb.transaction * type="Required"
假设这意味着配置的 ejb 事务属性是必需的,则容器强制执行对 delete()
业务方法的每次调用
在一笔交易内。
因此,划定事务边界不是问题,可以确定两个删除操作都在同一个事务中执行。
如果一个删除操作失败,您需要将事务标记为回滚。
更简单的方法是让您的业务方法抛出系统异常。
} catch (Exception e) {
//log exception
throw new EJBException();
}
当容器检测到抛出系统异常(在 ejb2.x 中,这只是从 RuntimeException 类扩展的异常)时, 它会自动将事务标记为回滚。但是,当抛出应用程序异常(从 Exception 扩展的异常)时, 容器不会改变事务状态。
就您而言,delete() 似乎会引发应用程序异常。
另一种选择是使用 SessionContext.setRollbackOnly() 显式标记事务以进行回滚方法。
//bean atribute
private SessionContext context;
//bean method call by the Container
public void setSessionContext(SessionContet ctx) {
context = ctx;
}
//your first delete code
try {
...
EJBLocalObject local_another_o = getEjbLocalObject(local_o.getAnotherId());
local_another_o.remove();
...
} catch (Exception e) {
context.setRollbackOnly();
//log exception
//throw new Exception
}
//idem for your second delete
关于java - EJB 2.0 CMP : exception scenario in multiple remove calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21301760/