简体   繁体   English

在Servlet会话中缓存Hibernate实体

[英]Caching Hibernate entity in a servlet session

Let's say, I cache the current user in a servlet session (or alike) and get a request like "get all books of the current user". 假设,我在Servlet会话 (或类似会话 )中缓存了当前用户,并收到了诸如“获取当前用户的所有书籍”之类的请求。 Naively, I'd go for 天真的,我会去

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

and this works, but in more complicated cases (which I can't reproduce now), I get a 这样就可以了,但是在更复杂的情况下(我现在无法重现),我得到了

TransientObjectException: object references an unsaved transient instance

So I thought, I should attach the current user to the session somehow. 所以我想,我应该以某种方式将当前用户附加到会话中。 I tried 我试过了

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

only to find out that it issues a database query, thus making the caching no better than storing the id only. 只是发现它发出了数据库查询,因此使缓存没有比仅存储id好。

Can such a caching be done efficiently? 这样的缓存可以有效地完成吗?

I would also recommend caching only the ID, rather than the entire entity. 我还建议仅缓存ID,而不缓存整个实体。 However, you are looking for the load(...) method intead of merge(...) or get(...). 但是,您正在寻找合并(...)或get(...)的load(...)方法。 The advantage of the load(...) method is that it simply generates an entity that is attached to your session without making a query to the database. load(...)方法的优点在于,它仅生成一个连接到您的会话的实体,而无需查询数据库。 Assuming that nobody else can come along and delete the record so that you know that your record still exists then the drawbacks to the load method (which are certainly there) are not relevant for your use-case. 假设没有其他人可以删除记录,以便您知道记录仍然存在,那么load方法的缺点(肯定存在)与您的用例无关。

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

This will give you an object that you can use to query as in your example 这将为您提供一个对象,您可以使用它来查询示例

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

Or else that you can also use to set in other entities while persisting 否则您还可以在持久化时用于设置其他实体

book.setUser(currentUser);

In the version of hibernate I tested with, accessing the hashCode(), toString() or equals() method caused the entity to be initialized, including a database query. 在我测试过的休眠版本中,访问hashCode(),toString()或equals()方法导致实体初始化,包括数据库查询。 But provided you only need to use it to query or set your foreign key references while persisting other entities, the load(Class, Serializable) method is what you are looking for. 但是只要持久化其他实体时只需要使用它来查询或设置外键引用,就可以找到load(Class,Serializable)方法。

Edited - What happens if record does not exist You get an ObjectNotFoundException. 编辑-如果记录不存在会发生什么情况您将获得ObjectNotFoundException。 It extends UnresolvableObjectException which extends HibernateException, which is of course, a RuntimeException. 它扩展了UnresolvableObjectException,后者扩展了HibernateException,它当然是RuntimeException。 This means that your code exits rather ungracefully (unless you want to catch this exception everywhere - but of course that it is not a reasonable solution) 这意味着您的代码会很不友好地退出(除非您想在任何地方捕获此异常-当然,这不是一个合理的解决方案)

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)

Why not cache the id only? 为什么不只缓存ID? For the Books query, you could simply do this: 对于“书籍”查询,您只需执行以下操作:

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

If you need the cached user object for other reasons, you could simply use currentUser.id , rather than currentUserId . 如果由于其他原因需要缓存的用户对象,则可以简单地使用currentUser.id而不是currentUserId

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM