简体   繁体   English

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

[英]JPA: How can I ensure that attribute values of a managed entity are written to the database in a transactional way?

It seems like a pretty basic question to me, so probably I'm either lacking the right search terms or I'm completely missing something about the way how managed entites work, but nevertheless I was unable to find out how to do this: Writing new attribute values of a managed entity to the database in a transactional way, meaning I want to set a bunch of values to an entity bean and have them persisted all at once and without other threads seeing a „dirty“ intermediate state of the bean or interrupting the writing process. 对我来说,这似乎是一个非常基本的问题,所以可能我缺少正确的搜索词,或者我完全缺少关于托管实体的工作方式的一些知识,但是我仍然找不到解决方法:受管实体的新属性值以事务性方式提供给数据库,这意味着我想为实体bean设置一堆值,并使它们一次全部持久化,而其他线程不会看到bean的“脏”中间状态或中断写作过程。

This is the entity class: 这是实体类:

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

I'm using it here: 我在这里使用它:

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

I need to ensure that no other thread can see the entity in a „half-written“ state, ie with the new status already persisted but the old value still present in the database. 我需要确保没有其他线程可以看到处于“半写”状态的实体,即新状态已经保留,但旧值仍存在于数据库中。 I tried using a lock: 我尝试使用锁:

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

But this throws: 但这引发了:

java.lang.IllegalArgumentException: entity not in the persistence context because the transaction used for reading the entity ends after the entityManager.find() is completed and therefore also the persistence context is gone, as I learned from this answer . java.lang.IllegalArgumentException: entity not in the persistence context因为用于读取实体的事务在entityManager.find()完成之后结束,因此持久性上下文也消失了,正如我从此答案中学到的。

Also, I read here that I cannot manually create transactions with an EntityManager that uses container-managed transactions. 另外,我在这里阅读到我无法使用使用容器管理的事务的EntityManager手动创建事务。 But isn't there any way now to manually ensure that the entity's attributes are persisted together (or not at all)? 但是,现在没有任何方法可以手动确保实体的属性一起(或根本不保留)吗? Or is this somehow already done automatically? 还是以某种方式已经自动完成?

Since you run in EJB container and your transaction is managed by the container, every business method of your EJB bean is invoked inside a transaction, so as far as your isolation level of the transaction is no set to Read uncommitted , changes that where made in the method will be visible when the transaction commits, that is when the method finishes. 由于您在EJB容器中运行,并且事务由该容器管理,因此,只要将事务的隔离级别设置为Read uncommitted ,就可以在事务内部调用EJB bean的每个业务方法。当事务提交时,即方法完成时,该方法将可见。

UPDATE: 更新:

As you don't use business methods it looks like your code is running without any transaction. 由于您不使用业务方法,因此看起来您的代码正在运行而没有任何事务。 In this case, every invocation of EnitytMangers method will create a new PersistenceContext. 在这种情况下,每次调用EnitytMangers方法都会创建一个新的PersistenceContext。 This is why you are getting exception. 这就是为什么您要例外。 Entity that you get form find method is detached when next method of EntityManager is called (as new PersistenceContext is created). 当调用EntityManager的下一个方法时(创建新的PersistenceContext时),将分离获得表单find方法的实体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM