Hibernate 中 session.get() 和 session.byId().load() 有什么区别?
What is difference between session.get() and session.byId().load() in Hibernate?
当对象被写入数据库并且主标识符 (id
) 已知时,可以通过以下代码检索它:
MyObject myObject = session.get(Class<MyObject>, id);
看来,还有一种类似于get()
的方法:
IdentifierLoadAccess<MyObject> ila = session.byId(Class<MyObject>);
MyObject myObject = ila.load(id);
我正在寻找一个场景来阐明它们之间的差异,并描述在 API 中对同一作业使用两种相似方法的原因。
关于 session.load()
和 session.byId().getReference()
可以问同样的问题。
编辑 1:
根据 API 文档:
session.get()
和 session.byId().load()
return 具有给定标识符的持久实例,如果没有这样的持久实例,则为 null。
session.load()
和 session.byId().getReference()
可能 return 一个按需初始化的代理实例。
get() 和 load() 方法之间的主要区别在于,如果找不到传递给它们的带有 id 的对象,load() 将抛出异常,而 get() 将 return null。另一个重要的区别是 load 可以 return 代理而不访问数据库,除非需要(当你访问 id 以外的任何属性时)但是 get() 总是去数据库,所以有时使用 load() 可以比获取()方法。如果您知道对象存在,则使用 load() 方法是有意义的,但如果您不确定对象是否存在,则使用 get() 方法。
之间的相似度
MyObject myObject = session.get(Class<MyObject>, id);
and
IdentifierLoadAccess<MyObject> ila = session.byId(Class<MyObject>);
MyObject myObject = ila.load(id);
两者都使用了休眠缓存机制的概念,但不同之处在于从数据库中获取数据,即
当我们使用 session.get(Class,id) 时,数据库中的数据进入缓存,您可以对该数据进行更改并反映出来回到数据库,因为休眠在内部维护一个时间戳缓存。此时间戳缓存记录特定 Hibernate 管理的 table 被修改的时间,并且在从实体缓存返回数据之前,它验证结果缓存是否相对于 table 修改时间更旧。
但是在 session.byId().getReference() 的情况下,hibernate 使用自然 id 的概念,其中来自数据库的数据进入缓存但只有 onces.If 您使用 session.save(entity object) 方法对该数据进行任何更改 hibernate 将抛出异常,如果您手动修改 table(insert,update,delete) 它不会被反映回来当您再次获取数据时,因为它总是从缓存中获取数据,而不检查该实体的 table 是否已再次修改。
在 session.get() 和 session.load() 的情况下如果数据库有任何变化就像记录的(插入、删除、更新)一样,如果在 session.byId().load() 和 [=30 的情况下记录得到 deleted.But,它将以记录或空指针异常的形式反映出来=]().getReference() 当您第一次尝试获取时,它将首先从数据库中获取记录,然后它将这些记录保存在会话中,并且只有在发生任何(插入、删除、更新)时才会从会话中显示给用户那么就不会反射回来
多用于多态association/queries。假设您有一个名为 User 的实体与 BillingDetails 关联。如果 BillingDetails 映射为
lazy="true"(这是默认值),Hibernate 将代理关联目标。在这种情况下,您将无法在运行时对具体的 class CreditCard(它是 BillingDetails 的子class)执行类型转换,甚至 instanceof 运算符的行为也会很奇怪:
User user = (User) session.get(User.class, userid);
BillingDetails bd = user.getDefaultBillingDetails();
System.out.println( bd instanceof CreditCard ); // Prints "false"
CreditCard cc = (CreditCard) bd; // ClassCastException!
要执行代理安全类型转换,请使用 load()
User user = (User) session.get(User.class, userId);
BillingDetails bd = user.getDefaultBillingDetails();
// Narrow the proxy to the subclass, doesn't hit the database
CreditCard cc =
(CreditCard) session.load( CreditCard.class, bd.getId() );
expiryDate = cc.getExpiryDate();
请注意,您可以通过避免延迟提取来避免这些问题,如以下代码所示,使用预先提取查询
User user = (User)session.createCriteria(User.class)
.add(Restrictions.eq("id", uid) )
.setFetchMode("defaultBillingDetails", FetchMode.JOIN)
.uniqueResult();
// The users defaultBillingDetails have been fetched eagerly
CreditCard cc = (CreditCard) user.getDefaultBillingDetails();
expiryDate = cc.getExpiryDate();
真正面向对象的代码不应该使用 instanceof 或大量类型转换。如果您发现自己 运行 遇到代理问题,您应该质疑您的设计,询问是否有更多的多态方法。
IdentifierLoadAccess
允许您指定:
LockOptions
CacheMode
甚至一次指定它们:
Post post = session
.byId( Post.class )
.with( new LockOptions( LockMode.OPTIMISTIC_FORCE_INCREMENT) )
.with( CacheMode.GET )
.load( id );
getting a Proxy reference 相同,通过 getReference(id)
。
因此,它们比仅采用实体标识符的标准 get
或 load
更灵活。
当对象被写入数据库并且主标识符 (id
) 已知时,可以通过以下代码检索它:
MyObject myObject = session.get(Class<MyObject>, id);
看来,还有一种类似于get()
的方法:
IdentifierLoadAccess<MyObject> ila = session.byId(Class<MyObject>);
MyObject myObject = ila.load(id);
我正在寻找一个场景来阐明它们之间的差异,并描述在 API 中对同一作业使用两种相似方法的原因。
关于 session.load()
和 session.byId().getReference()
可以问同样的问题。
编辑 1:
根据 API 文档:
session.get()
和session.byId().load()
return 具有给定标识符的持久实例,如果没有这样的持久实例,则为 null。session.load()
和session.byId().getReference()
可能 return 一个按需初始化的代理实例。
get() 和 load() 方法之间的主要区别在于,如果找不到传递给它们的带有 id 的对象,load() 将抛出异常,而 get() 将 return null。另一个重要的区别是 load 可以 return 代理而不访问数据库,除非需要(当你访问 id 以外的任何属性时)但是 get() 总是去数据库,所以有时使用 load() 可以比获取()方法。如果您知道对象存在,则使用 load() 方法是有意义的,但如果您不确定对象是否存在,则使用 get() 方法。
之间的相似度
MyObject myObject = session.get(Class<MyObject>, id);
and
IdentifierLoadAccess<MyObject> ila = session.byId(Class<MyObject>);
MyObject myObject = ila.load(id);
两者都使用了休眠缓存机制的概念,但不同之处在于从数据库中获取数据,即
当我们使用 session.get(Class,id) 时,数据库中的数据进入缓存,您可以对该数据进行更改并反映出来回到数据库,因为休眠在内部维护一个时间戳缓存。此时间戳缓存记录特定 Hibernate 管理的 table 被修改的时间,并且在从实体缓存返回数据之前,它验证结果缓存是否相对于 table 修改时间更旧。
但是在 session.byId().getReference() 的情况下,hibernate 使用自然 id 的概念,其中来自数据库的数据进入缓存但只有 onces.If 您使用 session.save(entity object) 方法对该数据进行任何更改 hibernate 将抛出异常,如果您手动修改 table(insert,update,delete) 它不会被反映回来当您再次获取数据时,因为它总是从缓存中获取数据,而不检查该实体的 table 是否已再次修改。
在 session.get() 和 session.load() 的情况下如果数据库有任何变化就像记录的(插入、删除、更新)一样,如果在 session.byId().load() 和 [=30 的情况下记录得到 deleted.But,它将以记录或空指针异常的形式反映出来=]().getReference() 当您第一次尝试获取时,它将首先从数据库中获取记录,然后它将这些记录保存在会话中,并且只有在发生任何(插入、删除、更新)时才会从会话中显示给用户那么就不会反射回来
多用于多态association/queries。假设您有一个名为 User 的实体与 BillingDetails 关联。如果 BillingDetails 映射为 lazy="true"(这是默认值),Hibernate 将代理关联目标。在这种情况下,您将无法在运行时对具体的 class CreditCard(它是 BillingDetails 的子class)执行类型转换,甚至 instanceof 运算符的行为也会很奇怪:
User user = (User) session.get(User.class, userid);
BillingDetails bd = user.getDefaultBillingDetails();
System.out.println( bd instanceof CreditCard ); // Prints "false"
CreditCard cc = (CreditCard) bd; // ClassCastException!
要执行代理安全类型转换,请使用 load()
User user = (User) session.get(User.class, userId);
BillingDetails bd = user.getDefaultBillingDetails();
// Narrow the proxy to the subclass, doesn't hit the database
CreditCard cc =
(CreditCard) session.load( CreditCard.class, bd.getId() );
expiryDate = cc.getExpiryDate();
请注意,您可以通过避免延迟提取来避免这些问题,如以下代码所示,使用预先提取查询
User user = (User)session.createCriteria(User.class)
.add(Restrictions.eq("id", uid) )
.setFetchMode("defaultBillingDetails", FetchMode.JOIN)
.uniqueResult();
// The users defaultBillingDetails have been fetched eagerly
CreditCard cc = (CreditCard) user.getDefaultBillingDetails();
expiryDate = cc.getExpiryDate();
真正面向对象的代码不应该使用 instanceof 或大量类型转换。如果您发现自己 运行 遇到代理问题,您应该质疑您的设计,询问是否有更多的多态方法。
IdentifierLoadAccess
允许您指定:
LockOptions
CacheMode
甚至一次指定它们:
Post post = session
.byId( Post.class )
.with( new LockOptions( LockMode.OPTIMISTIC_FORCE_INCREMENT) )
.with( CacheMode.GET )
.load( id );
getting a Proxy reference 相同,通过 getReference(id)
。
因此,它们比仅采用实体标识符的标准 get
或 load
更灵活。