何时将 EntityManager.find() 与 EntityManager.getReference() 与 JPA 一起使用 [英] When to use EntityManager.find() vs EntityManager.getReference() with JPA

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

问题描述

我遇到了一种情况(我认为这很奇怪但可能很正常),我使用 EntityManager.getReference(LObj.getClass(), LObj.getId()) 来获取数据库实体,然后通过返回的对象保存在另一个表中.

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

<前>类 TFacade{创建T(FObj,AObj){T TObj = 新 T();TObj.setF(FObj);TObj.setA(AObj);...EntityManager.persist(TObj);...L LObj = A.getL();FObj.setL(LObj);FFacade.editF(FObj);}}@TransactionAttributeType.REQUIRES_NEW类 FFacade{编辑F(FObj){L LObj = FObj.getL();LObj = EntityManager.getReference(LObj.getClass(), LObj.getId());...EntityManager.merge(FObj);...FLHFacade.create(FObj, LObj);}}@TransactionAttributeType.REQUIRED类 FLHFFacade{创建FLH(FObj,LObj){FLH FLHObj = 新的 FLH();FLHObj.setF(FObj);FLHObj.setL(LObj);....EntityManager.persist(FLHObj);...}}

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

研究了一段时间后,我终于发现是因为我使用了 EntityManager.getReference() 方法,所以我在该方法返回代理时遇到了上述异常.

这让我想知道,什么时候最好使用 EntityManager.getReference() 方法而不是 EntityManager.find() 方法?

EntityManager.getReference() 如果找不到正在搜索的实体,它会抛出一个 EntityNotFoundException 异常,这本身就非常方便.EntityManager.find() 方法仅在找不到实体时返回 null.

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

解决方案

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

public class Person {私人字符串名称;私人整数年龄;}公共类 PersonServiceImpl 实现 PersonService {public void changeAge(Integer personId, Integer newAge) {Person person = em.getReference(Person.class, personId);//人是代理person.setAge(newAge);}}

如果我调用 find 方法,JPA 提供者在幕后会调用

SELECT NAME, AGE FROM PERSON WHERE PERSON_ID = ?更新人设年龄 = ?WHERE PERSON_ID = ?

如果我调用 getReference 方法,JPA 提供者在幕后会调用

UPDATE PERSON SET AGE = ?WHERE PERSON_ID = ?

你知道为什么吗???

当你调用getReference时,你会得到一个代理对象.像这样的东西(JPA 提供者负责实现这个代理)

public class PersonProxy {//JPA provider在调用getReference时设置这个字段私人整数personId;私人字符串查询=更新人集";私有布尔 stateChanged = false;public void setAge(Integer newAge) {stateChanged = 真;查询 += 查询 + "AGE = " + newAge;}}

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

问候,

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

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

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.

This makes me wonder, when is it advisable to use the EntityManager.getReference() method instead of the EntityManager.find() method?

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.

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.

解决方案

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

}

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 = ?

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

UPDATE PERSON SET AGE = ? WHERE PERSON_ID = ?

And you know why ???

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

}

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.

regards,

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

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆