2012-06-27 65 views
1

首先,this解决方案不适合我,因为我无法更改持久性单元。JPA:如何使用与JTA EntityManager进行交易?

我的问题是,我使用JTA EntityManager的,但我需要整整一个用例类似交易:

public boolean saveWithResult(PointsValidityPeriod pointsValidityPeriod) 
{ 
    //TODO use transaction here 
    super.save(pointsValidityPeriod); 

    if (updatePrevious(pointsValidityPeriod.getValidFrom()) != 1) 
    { 
     logger.error("Update of Period was not possible, because UPDATE returned no single result."); 

     return false; 
    } 

    pointsValidityPeriodEvent.fire(pointsValidityPeriod); 

    return true; 
} 

保存方法(我不能改变):

public void save(T entity) 
{ 
    getEntityManager().persist(entity); 
} 

你会看到,有一个保存调用,但是如果更新出错,这个保存必须回退,那么我该如何实现呢?有任何想法吗?

+0

JTA的重点在于管理交易。你在哪个环境中执行你的应用程序?具有EJB的应用程序服务器?然后使用EJB来划分交易:这是他们的主要观点。 –

+0

是的,我们在JBoss中使用EJB。 – Bevor

+0

默认情况下,EJB是事务性的。默认情况下,EJB方法中的所有代码都是在事务中执行的。 –

回答

0

我有解决方案,但我不知道为什么这个工程。也许有人可以向我解释。 在我的支持bean中有保存方法。有2个实体。 getEntity()是支持bean使用的当前实体,currentValidityPeriod是该实体的另一个实例,该实体持有实体的最新数据库状态,由currentValidityPeriod = pointsValidityService.findCurrent()提取。 findCurrent()是只是其中执行TypedQuery的方法:

public PointsValidityPeriod findCurrent() 
{ 
    TypedQuery<PointsValidityPeriod> validityPeriodQuery = entityManager.createNamedQuery(PointsValidityPeriod.FindCurrent, PointsValidityPeriod.class); 

    return validityPeriodQuery.getSingleResult(); 
} 

这是由视图调用保存方法。如您所见,我只将当前实体传递给服务保存方法。在之前的实体(currentValidityPeriod)中,我设置了另一个值。

@Override 
public void save() 
{  
    Date validFrom = new DateTime(DateTimeZone.forID("Europe/Vienna")).toDate(); 
    getEntity().setValidFrom(validFrom); 

    currentValidityPeriod.setValidThru(validFrom); 

    pointsValidityService.save(getEntity()); 

    addSavedSuccessfullyMessage(); 
} 

这是服务方法将被调用:

@Override 
public void save(PointsValidityPeriod pointsValidityPeriod) 
{ 
    super.save(pointsValidityPeriod); 
} 

...和超类的保存方法:

public void save(T entity) 
{ 
    getEntityManager().persist(entity); 
} 

为什么实体管理器持久化新的实体和更新旧的?我只是通过ONE实体到实体管理器。虽然这是预期的行为,但我想知道为什么这会起作用。

+1

当您处于事务中时,JPA提供程序需要在事务提交时同步处于'managed'状态的实体状态与数据库。换句话说,如果你在事务中从数据库中获取实体并且改变它的状态,在tx commit期间它会自动对这个实体执行'更新'。 –

1

这一切都取决于您的方法事务注释。如果您没有,那么默认情况下,事务边界设置为业务方法,如JB所指。

因此,整个方法是一个事务。通常情况下,save方法的交易管理很重要(如果是REQUIREDREQUIRES_NEW),但在这种情况下,您正在进行本地方法调用 - 而不是业务方法调用,因此任何用于save方法的交易管理设置在这里不适用。

因此,如果update失败可以上自动事务回滚为碱(如果它是一个EntityManager呼叫其生成回滚的Tx除外)也可以手动注入SessionContext和线之间在其上调用setRollbackOnly(),东西:

@Resource 
SessionContext ctx; 

public boolean saveWithResult(PointsValidityPeriod pointsValidityPeriod) 
{ 
    // ... 
    if (updatePrevious(pointsValidityPeriod.getValidFrom()) != 1) 
    { 
     // ... 
     ctx.setRollbackOnly(); 
     // ... 
    } 
} 
+0

不幸的是我不能这样做。 Eclipse向我展示了“没有bean有资格注入注入点[JSR-299§5.2.1]”,并且最终在启动JBoss时导致异常:org.jboss.weld.exceptions.DeploymentException:WELD-001408 Unsatisfied类型为[SessionContext]的依赖关系具有限定符[@Default]在注入点[[field] @Inject – Bevor

+0

注解不应该是@Resource?有关如何从EJB获取SessionContext,请参阅http://javahowto.blogspot.fr/2006/06/4-ways-to-get-ejbcontext-in-ejb-3.html。 –

+0

啊,当然是JB - '@ Resource'!抱歉的家伙,太多的CDI让我变成一个无聊的男孩! –