Spring Boot和Spring Data:Hibernate会话是如何管理的?

87

我目前正在开发一个使用Spring Boot和Spring Data(特别是它的JpaRepository接口)以及Hibernate的应用程序。

我喜欢Hibernate的缓存功能,当您提交多个查询与特定对象匹配时,您将在每次查询执行中返回该对象的同一实例(关于Java的==运算符)。然而,在使用Spring Data和JpaRepository类时,这似乎并不总是如此。出于这个原因,我认为这里有多个HibernateSession实例在工作。

我的问题是:Spring Data如何处理Hibernate会话?它何时打开或关闭它们?是否有一种方法可以配置它在整个应用程序的运行时期使用相同的会话,以充分利用Hibernate的对象缓存?是否有理由这样做?

谢谢,

Alan

1个回答

115

我想我已经找到了答案。如果有人发现这个问题,这是我的答案。

Spring 如何管理 Hibernate 会话?

默认情况下,Spring Boot 在仓库级别应用事务管理。在这种情况下,当调用 JpaRepository 方法(或者一般的 Repository 方法)时,Spring 将会:

  • 要求 SessionFactory 创建新的 session
  • 打开此 session
  • 开启事务
  • 执行所调用的 Repository 方法
  • 关闭事务
  • 关闭 session

然而,如果你将 @Transactional 应用于服务类或方法,Spring 将会在进入服务方法时打开 session 和事务,并在现有事务中执行仓库方法。

会有什么后果?

作为程序员...

  • 你完全不需要关心事务或 session。
  • 如果你想依赖 Hibernate 的缓存功能,你必须在比仓库更大的范围上指定 @Transactional。缓存只在同一个 HibernateSession 中有效。
  • 你必须通过它们的 Hibernate ID 值来确定你的 @Entity 对象的等价性,而不能使用 Java 的 == 运算符。
  • 你需要注意懒加载集合(例如在 @OneToMany 引用中)在你的 @Entity 类中(参见 FetchMode.LAZYFetchMode.EAGER)只能在有 @Transactional 注释的方法中使用。

另外作为参考,以下链接非常有帮助:Multiple Transactions in single session

就像Spring的许多其他方面一样,如果您愿意牺牲对应用程序的直接控制权,则可以从中获得很多收益。


14
实际上那不是真的...根据您的交易标记,您将重复使用已经打开的会话。如果您有一个带有@Transactional注释的服务方法(并且已经正确设置了tx支持),Spring将打开一个Session / EntityManager并在该事务中重复使用它以进行所有数据库调用。还应注意,您的服务层应该是事务层,而不是数据访问层。 - M. Deinum
@M.Deinum 你好,我是新手使用Spring Boot。我的问题也与此有关。如果我使用jpaRepository,是否需要使用SessionFactory?如果有多个请求,Spring Boot是否会自动处理会话?希望能收到您对我的问题的答复。https://stackoverflow.com/questions/51764684/does-sessionfactory-or-entitymanager-use-with-jpa-repositories - varman
1
我进行了编辑以澄清默认事务标记在存储库上的行为,与用@Transactional注释服务方法的区别。 - Andrew Spencer
8
请注意,在Web应用程序中,默认情况下,Spring Boot将创建一个开放的“实体管理器视图”,这意味着Hibernate会话(在EntityManager后面)将持续整个HTTP请求处理过程。事务仍将在进入@Transactional方法时创建,但将使用现有的EntityManager。 - Andrew Spencer
这个答案是不正确的。请查看 @AndrewSpencer 的评论,那个是正确的。 - ACV
@M.Deinum 如果我理解正确的话,对于例如JpaRepository这样的类,Spring会创建一个HibernateSession,但是你无法访问那些被延迟初始化的实体的子元素,这是正确的吗? - Andreea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接