Search code examples
javatransactionsjpa-2.0entitymanagerjta

JPA: How to use transactions with JTA EntityManager?


First of all, this solution is no option for me, because I can't change the persistence-unit.

My problem is that I use a JTA EntityManager but I need for exactly one use case something like a transaction:

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;
}

Save method (which I can't change):

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

You see, that there is a save invocation, but this save must be rolled back if the update went wrong, so how can I achieve that? Any ideas?


Solution

  • I have the solution but I don't know why this works. Maybe someone could explain it to me. In my backing bean there is the save method. There are 2 entities. getEntity() is the current entity used by the backing bean, currentValidityPeriod is another instance of that Entity which holds the latest database state of the entity, fetched by currentValidityPeriod = pointsValidityService.findCurrent(); findCurrent() is just a method which executes a TypedQuery:

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

    This is the save method invoked by the view. As you can see, I only pass the current Entity to the service save method. In the previous Entity (currentValidityPeriod), I set another value.

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

    This is the service method which will be invoked:

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

    ...and Superclass's save method:

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

    Why does the Entity Manager persist the new Entity and update the old one? I just pass ONE Entity to the Entity Manager. Although this is the expected behavior, I'd like to know why this works.