本文介绍了何时使用EntityManager.find()与EntityManager.getReference()一起使用JPA的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到过一种情况(我觉得很奇怪,但可能很正常),我使用EntityManager.getReference(LObj.getClass(),LObj.getId())获取数据库实体,然后传递返回的对象将保留在另一个表中。

I have come across a situation (which I think is weird but is possibly quite normal) where I use the EntityManager.getReference(LObj.getClass(), LObj.getId()) to get a database entity and then pass the returned object to be persisted in another table.

所以基本上流程是这样的:

So basically the flow was like this:


class TFacade{

  createT(FObj, AObj) {
    T TObj = new T();
    TObj.setF(FObj);
    TObj.setA(AObj);
    ...
    EntityManager.persist(TObj);
    ...
    L LObj = A.getL();
    FObj.setL(LObj);
    FFacade.editF(FObj);
  }
}

@TransactionAttributeType.REQUIRES_NEW
class FFacade{

  editF(FObj){
    L LObj = FObj.getL();
    LObj = EntityManager.getReference(LObj.getClass(), LObj.getId());
    ...
    EntityManager.merge(FObj);
    ...
    FLHFacade.create(FObj, LObj);
  }
}

@TransactionAttributeType.REQUIRED
class FLHFacade{

  createFLH(FObj, LObj){
    FLH FLHObj = new FLH();
    FLHObj.setF(FObj);
    FLHObj.setL(LObj);
    ....
    EntityManager.persist(FLHObj);
    ...
  }
}

我收到以下异常 java.lang.IllegalArgumentException:未知实体:com.my.persistence.L $$ EnhancerByCGLIB $$ 3e7987d0

I was getting the following exception "java.lang.IllegalArgumentException: Unknown entity: com.my.persistence.L$$EnhancerByCGLIB$$3e7987d0"

看了一会儿后,我终于想通了这是因为我正在使用EntityManager.getReference()方法,因为该方法正在返回代理,我得到了上述异常。

After looking into it for a while, I finally figured out that it was because I was using the EntityManager.getReference() method that I was getting the above exception as the method was returning a proxy.

这让我想知道,何时建议使用EntityManager.getReference()方法而不是EntityManager.find()方法

EntityManager.getReference()抛出EntityNotFoundException,如果它找不到被搜索的实体本身就很方便。如果EntityManager.find()方法找不到实体,它只返回null。

EntityManager.getReference() throws an EntityNotFoundException if it cant find the entity being searched for which is very convenient in itself. EntityManager.find() method merely returns null if it cant find the entity.

关于事务边界,听起来像你需要使用find()在将新找到的实体传递给新事务之前的方法。如果你使用getReference()方法,那么你可能最终会遇到类似我的情况,但上述例外。

With regards to transaction boundaries, sounds to me like you would need to use the find() method before passing the newly found entity to a new transaction. If you use the getReference() method then you would probably end up in a situation similar to mine with the above exception.

推荐答案

当我不需要访问数据库状态时(我的意思是getter方法),我通常使用 getReference 方法。只是改变状态(我的意思是设定方法)。您应该知道,getReference返回一个代理对象,该对象使用称为自动脏检查的强大功能。假设以下

I usually use getReference method when i do not need to access database state (I mean getter method). Just to change state (I mean setter method). As you should know, getReference returns a proxy object which uses a powerful feature called automatic dirty checking. Suppose the following

public class Person {

    private String name;
    private Integer age;

}


public class PersonServiceImpl implements PersonService {

    public void changeAge(Integer personId, Integer newAge) {
        Person person = em.getReference(Person.class, personId);

        // person is a proxy
        person.setAge(newAge);
    }

}

如果我打电话给发现方法,JPA提供商,在幕后,将调用

If i call find method, JPA provider, behind the scenes, will call

SELECT NAME, AGE FROM PERSON WHERE PERSON_ID = ?

UPDATE PERSON SET AGE = ? WHERE PERSON_ID = ?

如果我调用 getReference 方法,JPA提供商,在幕后,将致电

If i call getReference method, JPA provider, behind the scenes, will call

UPDATE PERSON SET AGE = ? WHERE PERSON_ID = ?

你知道为什么???

当您调用getReference时,您将获得一个代理对象。像这样的东西(JPA提供商负责实现这个代理)

When you call getReference, you will get a proxy object. Something like this one (JPA provider takes care of implementing this proxy)

public class PersonProxy {

    // JPA provider sets up this field when you call getReference
    private Integer personId;

    private String query = "UPDATE PERSON SET ";

    private boolean stateChanged = false;

    public void setAge(Integer newAge) {
        stateChanged = true;

        query += query + "AGE = " + newAge;
    }

}

因此,在交易提交之前,JPA提供商将看到stateChanged标志以更新OR NOT person实体。如果在update语句之后没有更新行,JPA提供程序将根据JPA规范抛出EntityNotFoundException。

So before transaction commit, JPA provider will see stateChanged flag in order to update OR NOT person entity. If no rows is updated after update statement, JPA provider will throw EntityNotFoundException according to JPA specification.

问候,

这篇关于何时使用EntityManager.find()与EntityManager.getReference()一起使用JPA的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 19:45