Hibernate实体存储为HttpSession属性值

我正在处理一个带有大量相当混乱的代码库的遗留Java应用程序。 有一个相当标准的“用户”对象存储在请求之间的HttpSession中,因此servlet在顶部执行如下操作:

HttpSession session = request.getSession(true); User user = (User)session.getAttribute("User"); 

旧的用户身份validation层(我将不会描述;足以说,它没有使用数据库)正被替换为使用Hibernate映射到数据库的代码。 所以’User’现在是一个Hibernate实体。

我对Hibernate对象生命周期的理解有点模糊,但似乎在HttpSession中存储’User’现在成为一个问题,因为它将在下一个请求期间在不同的事务中被检索。 在这里做什么是正确的? 我可以使用Hibernate Session对象的update()方法在下次重新附加User实例吗? 我需要吗?

假设您正在为每个请求 – 响应周期创建一个新的hibernate会话,可以将一个分离的对象合并到新的hibernate会话中,但我会完全避免这种方法。

而是尝试在HttpSession上存储一个密钥,该密钥可用于通过hibernate查找每个传入请求的用户。 如果您担心访问数据库以检索可以存储在HttpSession中的内容的性能影响,请不要担心 – 您可以始终使用hibernate支持的缓存框架来减少数据库访问次数。 提高性能的另一种方法是使用乐观锁定。

虽然我没有看过hibernate源代码,但我认为hibernate使用了“Identity Map”模式。 这是一个Map,它使用实体的id作为Map中的键,并将关联的实体对象用作Map中的值。 每当从hibernate会话中检索实体时,hibernate将查看会话的身份映射以查看它是否存在。 如果它在那里它将从地图返回实体。 如果不存在,它将从数据库中检索实体并将其放在地图上,然后返回实体。 这意味着,对于给定的hibernate会话,使用相同密钥(即id,userId等)访问给定User的连续查询将接收对同一User对象的引用,因此每个查询将能够“看到”对另一个查询的User对象。 因此,为每个传入请求创建一个新的hibernate会话是绝对必要的,这样对给定用户的并发请求就不必将其各自的线程锁定在它们的公共User对象上。 不同的hibernate会话将各自拥有自己的标识映射,因此不会返回对同一User对象的引用。

通过尝试将来自HttpSession的User对象合并到你的hibernate会话中,你基本上是试图直接操作hibernate的IdentityMap,用其他东西代替任何hibernate“思考”应该存在的东西,可以理解这可能会导致问题。 正如我所说虽然可以将一个分离的对象附加回一个hibernate会话,但我会避免它。 祝你采取任何方法都好运。

我强烈建议您阅读以下内容,特别是关于长对话和分离对象的部分:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

取决于用户是否在会话期间更改,或者您是否只需要id,name等进行快速查找。 您始终可以合并()来自数据库的用户,以便再次在会话中使用它。

您不需要每次都合并用户,因为它是一个您并不总是需要的数据库命中。 但是使用merge,您可以将用户重新连接到当前会话。

使用session.merge(..)

(来自Session的文档):

通过调用merge(),瞬态或分离实例的状态也可以作为新的持久实例持久化。

请务必正确覆盖hashCode()equals()