这对我来说似乎是一个非常基本的问题,所以我可能要么缺少正确的搜索字词,要么我完全错过了有关管理网站的工作方式,但我仍然无法找到如何执行此操作:以事务方式将托管实体的新属性值写入数据库,这意味着我想将一堆值设置为实体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手动创建事务。但是现在还没有办法手动确保实体的属性是一起存在的(或者根本不存在)?或者这是否已经自动完成了?
答案 0 :(得分:1)
由于您在EJB容器中运行并且您的事务由容器管理,因此EJB bean的每个业务方法都在事务内部调用,因此,事务的隔离级别未设置为读取未提交,在事务提交时,即方法完成时,可以看到方法中所做的更改。
<强>更新强>
由于您不使用业务方法,因此您的代码似乎在没有任何事务的情况下运行。在这种情况下,每次调用EnitytMangers方法都会创建一个新的PersistenceContext。
这就是你得到例外的原因。当调用EntityManager的下一个方法时(因为创建了新的PersistenceContext),您将获得从find
方法获取的实体。