2016-02-21 95 views
0

比方说,我将当前用户缓存在servlet会话(或类似)中,并获得“获取当前用户的所有书籍”之类的请求。天真,我会去在servlet会话中缓存Hibernate实体

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user", currentUser)) 
.list(); 

和工作原理,但在更复杂的情况(我现在不能重现),我得到一个

TransientObjectException: object references an unsaved transient instance 

所以我想,我应该重视不知怎的,当前用户到会话。我试图

currentUser = (User) session.merge(currentUser); 

才发现,它发出数据库查询,从而使缓存不超过只存储ID更好

这样的缓存可以有效地完成吗?

回答

2

我也建议只缓存ID而不是整个实体。但是,您正在查找merge(...)或get(...)的load(...)方法intead。 load(...)方法的优点是只需生成连接到会话的实体而不对数据库进行查询。假设没有其他人可以出现并删除记录,以便您知道您的记录仍然存在,那么加载方法的缺点(当然存在)与您的用例无关。

https://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/Session.html#load(java.lang.Class, java.io.Serializable)

这会给你一个对象,你可以用它来查询作为你的榜样

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user", currentUser)) 
.list(); 

要不然,你也可以使用其他实体来设置,而持续

book.setUser(currentUser); 

在我测试过的hibernate版本中,访问hashCode(),toString()或equals()方法导致实体初始化,包括一个数据库查询。但是,如果您只需要使用它来查询或设置外键引用,同时使其他实体持久化,那么load(Class,Serializable)方法就是您正在寻找的方法。

已编辑 - 如果不存在记录会发生什么 您将得到一个ObjectNotFoundException。它扩展了UnresolvableObjectException,它扩展了HibernateException,当然这是一个RuntimeException。这意味着你的代码退出而笨拙地(除非你要到处捕获这个异常 - 但当然,这是不是一个合理的解决方案)

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.yourcode.YourEntity#id that does not exist] 
at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419) 
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:154) 
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:143) 
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174) 
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) 
at com.yourcode.YourEntity_$$_javassist_143.getNonIdentifierMethod(YourEntity_$$_javassist_143.java) 
at com.yourcode.YourBusinessLogic.method(YourBusinessLogic.java:56) 
+0

非常感谢,我想这就是我以后的感受。你可以添加一些有关在使用带有被删除实体的'load'时发生的灾难的信息吗?这不是我问题的一部分,但是我从来没有从Hibernate文档中理解。 – maaartinus

1

为什么不缓存唯一的ID?对于图书的查询,你可以简单地这样做:

hibernateSession 
.createCriteria(Book.class) 
.add(Restrictions.eq("user.id", currentUserId)) 
.list(); 

如果需要其他原因缓存的用户对象,你可以简单地使用currentUser.id,而不是currentUserId

+0

肯定,但'Book'创建我需要的'user'本身。也许我可以使用一些级联合并...(至今为止,我避免级联,因为我更愿意明确说明这一点)。 – maaartinus

+0

合并(或加载)方法仍然具有性能优势,因为您只需访问持久实体以执行某些操作。我猜想在你的应用程序中,审阅图书清单比创建新书更经常。 –