Java EntityManager.find()和EntityManger.getReference()之间的区别是什么?

Java EntityManager.find()和EntityManger.getReference()之间的区别是什么?,java,jpa,entitymanager,Java,Jpa,Entitymanager,它们之间有什么区别 <T> T EntityManager.find(Class<T> entityClass, Object primaryKey) and <T> T EntityManager.getReference(Class<T> entityClass, Object primaryKey) 要将托管实体传递给entitymanager remove方法“什么是更好和正确的选项?”?查找或获取引用?getReference()不

它们之间有什么区别

<T> T EntityManager.find(Class<T> entityClass, Object primaryKey) and 
<T> T EntityManager.getReference(Class<T> entityClass, Object primaryKey) 
要将托管实体传递给entitymanager remove方法“什么是更好和正确的选项?”?查找或获取引用?

getReference()
不检索完整对象,而只检索代理,因此,如果不访问对象的成员,效率会更高

例如,在创建要插入数据库的新对象时,它可能必须引用已存储在数据库中的另一个对象

JPA要正确存储新对象,只需要引用对象的主键。
通过使用
getReference()
您可以获得一个包含主键的代理,并且可以节省加载整个对象的成本。

JPA具有EntityManager的概念,如您所知。在实体管理器中工作期间,一些对象从数据库加载,可以修改,然后刷新到数据库中

find()
必须返回对象的初始化实例。如果尚未在EntityManager中加载,则从数据库中检索

如果实体以前没有加载到EntityManager中,则允许
getReference()
返回代理而不是初始化的实例。在此代理中,仅初始化主键属性可以创建代理而无需访问数据库,因为唯一初始化的属性已经被赋予getReference()函数

当实体A引用实体B,并且希望将A的B属性设置为B,而不必从数据库中加载B时,后者非常有用

只有在引用B的其他属性时,代理才会被初始化。

在本书中,请在第135页“按ID查找”中提及差异

find()
如果找到实体,则返回实体;如果未找到,则返回空值

MyEntity obj = em.find(MyEntity.class, id);
if(obj != null){
   // Process the object 
}
getReference()
适用于需要托管实体实例,但除了实体的主键之外,不需要访问任何数据的情况

try {
    MyEntity obj = em.getReference(MyEntity.class, id);
    // Process the object
} catch (EntityNotFoundException e) {
    // Entity Not Found
}

这个类命名了一个不同的。。。其中一个与牲畜饲养实体有关:-)可能重复了卓越的解释。谢谢你,丹尼尔。如果实体已经加载了,就没有区别了,对吗?实际上getReference返回的对象不一定是任何“代理”,因为这是一个实现细节;一些将返回一个“代理”,而其他(支持字节码增强)将返回一个实际类型但延迟加载的对象。虽然在调用此方法时避免了数据库命中,但在以后加载字段时可能会得到多个数据库访问一个需要提前注意的警告:将getReference()与继承结合起来可能会导致“instanceof”以预期的方式运行。有很多方法可以解决这个问题,主要是使用访客模式,这里讨论:@Daniel如果getReference调用的实体中有版本注释会发生什么?没什么特别的,我们也使用@Version。而且版本不相关,因为它不是密钥的一部分。它仅在保存相关实体时使用。
try {
    MyEntity obj = em.getReference(MyEntity.class, id);
    // Process the object
} catch (EntityNotFoundException e) {
    // Entity Not Found
}