EntityManager.find() 和 EntityManger.getReference() 有啥区别?
Posted
技术标签:
【中文标题】EntityManager.find() 和 EntityManger.getReference() 有啥区别?【英文标题】:What is the difference between EntityManager.find() and EntityManger.getReference()?EntityManager.find() 和 EntityManger.getReference() 有什么区别? 【发布时间】:2011-07-25 19:48:47 【问题描述】:有什么区别
<T> T EntityManager.find(Class<T> entityClass, Object primaryKey) and
<T> T EntityManager.getReference(Class<T> entityClass, Object primaryKey)
?
我认为 getReference 如果它是托管的,它会返回实体。 如果它是托管的,则 find 返回实体,否则在数据库上执行 SQL 以使其托管。
请确认。
上下文: 从 webapp 我得到要删除的对象的主键(长类型的 pk);到实体应该被管理删除。
EntityManager.remove(Object entity)
将托管实体传递给 entitymanager remove 方法'什么是更好和正确的选择?查找或获取引用?'
【问题讨论】:
这个类命名了一个不同的......其中一个与给牲畜喂食有关:-) When to use EntityManager.find() vs EntityManager.getReference()的可能重复 【参考方案1】:如您所知,JPA 有 EntityManager 的概念。在实体管理器中工作期间,一些对象会从数据库中加载,可以修改并随后刷新到数据库中。
find()
必须返回对象的初始化实例。如果它尚未加载到 EntityManager 中,则从数据库中检索它。
getReference()
被允许返回一个代理而不是一个初始化的实例,如果该实体之前没有被加载到 EntityManager 中。在这个代理中,只有主键属性被初始化。 可以在不访问数据库的情况下创建代理,因为唯一的初始化属性已经提供给 getReference() 函数。
当您有一个实体 A 引用一个实体 B,并且您想将 A 的 b 属性设置为 B,而不必从数据库加载 B 时,后者很有用。
只有当你引用B的其他属性时,才会初始化代理。
【讨论】:
很好的解释。谢谢丹尼尔。如果实体已经加载,没有区别吗? 实际上 getReference 返回的对象不一定是任何“代理”,因为这是一个实现细节;有些将返回“代理”,而其他(支持字节码增强)将返回真实类型但延迟加载的对象。虽然您避免了调用此方法时的数据库命中,但稍后在加载字段时可能会获得多个数据库访问 一个需要提前注意的警告:将 getReference() 与继承结合可能会导致 'instanceof' 以预期的方式运行。有一些方法可以解决这个问题,主要是使用访问者模式,在这里讨论:***.com/questions/3540489/… @Daniel 如果 getReference 调用的实体中有版本注释会发生什么? 没什么特别的AFAIK,我们也使用@Version。并且版本不相关,因为它不是密钥的一部分。它仅在保存相关实体时使用。【参考方案2】:Beginning Java EE 6 Platform with GlassFish 3这本书,在第135页提到不同之处:“Finding By 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
【讨论】:
【参考方案3】:getReference()
不检索完整对象,而仅检索代理,因此如果您不访问对象的成员,效率会更高。
例如,在创建要插入数据库的新对象时,它可能必须引用已存储在数据库中的另一个对象。
为了让 JPA 正确存储新对象,只需要引用对象的主键。
通过使用getReference()
,您可以获得一个包含主键的代理,并节省了加载完整对象的成本。
【讨论】:
以上是关于EntityManager.find() 和 EntityManger.getReference() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
何时将 EntityManager.find() 与 EntityManager.getReference() 与 JPA 一起使用
EntityManager.find(id) 会执行恶意攻击吗?