JPA:如何确保以事务方式将托管实体的属性值写入数据库?

时间:2015-08-31 11:02:07

标签: java java-ee jpa

这对我来说似乎是一个非常基本的问题,所以我可能要么缺少正确的搜索字词,要么我完全错过了有关管理网站的工作方式,但我仍然无法找到如何执行此操作:以事务方式将托管实体的新属性值写入数据库,这意味着我想将一堆值设置为实体bean,并让它们一次性持久化而没有其他线程看到“脏” “bean的中间状态或打断写作过程。

这是实体类:

@Entity
public class MyEntityClass
{
    ...
    private String status;
    private String value;
    ...
    public void setStatus(String status)
    {
    ...
    public void setValue(String vlaue)
    {
    ...
}

我在这里使用它:

import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class MyService
{
    @PersistenceContext
    protected EntityManager entityManager;
    ...
    MyEntityClass entity = entityManager.find(entityClass, id);

    //Now I'd like to set some attributes in a transactional way
    entity.setStatus(newStatus);

    //what if the new status got persisted and another thread reads from the database now
    entity.setValue(newValue);

    //flushing, just to make sure that at least from here on the database is in a consistent state
    entityManager.flush();
}

我需要确保没有其他线程可以看到处于“半写”状态的实体,即新状态已经保留,但旧值仍然存在于数据库中。我试过用锁:

...
MyEntityClass entity = entityManager.find(entityClass, id);
entityManager.lock(entity, LockModeType.WRITE);
entity.setStatus(newStatus);
entity.SetValue(newValue);
entityManager.flush();
entityManager.lock(entity, LockTypeMode.NONE);
...

但是这引发了:

java.lang.IllegalArgumentException: entity not in the persistence context 因为用于阅读实体的事务在entityManager.find()完成后结束,因此持久化上下文也消失了,正如我从this answer学到的那样。

另外,我读到here我无法使用容器管理的事务的EntityManager手动创建事务。但是现在还没有办法手动确保实体的属性是一起存在的(或者根本不存在)?或者这是否已经自动完成了?

1 个答案:

答案 0 :(得分:1)

由于您在EJB容器中运行并且您的事务由容器管理,因此EJB bean的每个业务方法都在事务内部调用,因此,事务的隔离级别未设置为读取未提交,在事务提交时,即方法完成时,可以看到方法中所做的更改。

<强>更新

由于您不使用业务方法,因此您的代码似乎在没有任何事务的情况下运行。在这种情况下,每次调用EnitytMangers方法都会创建一个新的PersistenceContext。 这就是你得到例外的原因。当调用EntityManager的下一个方法时(因为创建了新的PersistenceContext),您将获得从find方法获取的实体。