【问题标题】:Best way to handle Hibernate Sessions in a layered Spring MVC Web application在分层 Spring MVC Web 应用程序中处理 Hibernate 会话的最佳方式
【发布时间】:2011-07-17 05:51:16
【问题描述】:

如果我们有一个 Web 应用程序具有

  • 繁重的 UI(Spring MVC + JQuery 与 JSON)
  • Hibernate 使用 JPA 注释作为域模型
  • 将 Spring 提供的 DAO 扩展到代码 DAO 层
  • JBOSS 是应用服务器,Oracle 作为后端
  • 基于数据源 (JNDI) 的连接池(不是 XA 而是本地数据源)
  • 还可以访问多个数据源(处理多个 DB)

在行为上,大量数据检索 (70%) 和数据更新为 30%
以下如何有效使用数据库连接并确保连接使用没有太多泄漏的最佳实践是什么?

  1. 选择基于 Hibernate 模板的 DAO 会更好吗?
  2. 什么样的事务管理器是值得推荐的,我们应该在哪里进行基于 AOP 的事务管理
  3. 在哪里实例化会话以及在哪里关闭会话以有效地使用来自连接池的连接。
  4. 确实,我们需要处理来自服务层的事务,但是会话会发生什么情况,它们会等待更长的时间(我们没有使用任何 opensessioninviewFilter)
  5. 哪个层更好地处理已检查异常(业务异常)和运行时异常。

抱歉,这个问题有点冗长,但我发现这是一个常见的查询,我尝试将其合并。感谢您的耐心和指导。谢谢你的帮助。

【问题讨论】:

  • 如果我们计划在后端使用数据库分区(表范围/哈希分区)怎么办。 Hibernate(或 Shards?尚未投入生产!)是否支持?

标签: java hibernate spring


【解决方案1】:

这听起来像是一个非常典型的 Spring/Hibernate 应用程序,所以我建议遵循我最近在 another answer 中概述的当前最佳实践。具体来说:

  1. 扩展 Spring DAO 支持类或使用 HibernateTemplate。将@Repository 注释与组件扫描结合使用,并将directly inject the SessionFactory 用于您的DAO。
  2. 使用 Spring 的 HibernateTransactionManager,并且绝对使用 declarative transaction management 通过 @Transactional 作为默认方法。
  3. Spring manage that。默认情况下,它将及时为事务打开会话,但更喜欢 Spring 的 OpenSessionInViewFilter 启用的 open session in view pattern
  4. 参见 #3。
  5. 总是在应该处理的地方处理异常——换句话说,这是一个设计决定。但是请注意,默认情况下 Spring 事务框架 rolls back on unchecked exceptions,但未选中,以匹配 EJB 规范的行为。确保在使用检查异常的任何地方设置正确的回滚规则(请参阅上一个链接)。

另外,显然使用连接池。 Apache Commons DBCP 是一个不错的选择。 “连接使用没有太多泄漏”是不够的。你必须有零连接泄漏。依靠 Spring 来管理您的资源将有助于确保这一点。至于任何其他性能问题,请不要过早地尝试优化。等到你看到问题所在,然后找出单独解决每个问题的最佳方法。由于您的瓶颈很可能与数据库有关,请查看 Hibernate 参考的the performance chapter 以了解您遇到的问题。它涵盖了缓存和获取策略的重要概念。

【讨论】:

  • 我更喜欢 EntityManager 而不是 SessionFactory
  • @Bozho:使用哪个并不重要,尽管我从未听说过使用 EntityManager 的令人信服的理由。
  • 这是标准的。如果在某些时候 hibernate 失败了,你几乎可以毫不费力地直接使用 EclipseLink
  • @Bozho:在这一点上,hibernate 比标准更加成熟和成熟——更不用说标准基本上是从 hibernate 构建的——我很乐意坚持直接休眠交互以避免 JPA 似乎带来的额外复杂性。 (
  • 在过去的 2 年里,我一直在使用 ir 和 jpa,它非常好。特别是。与 jpa2
【解决方案2】:
  • 直接在您的 DAO 中使用 JPA EntityManager。请务必不要将其标记为扩展
  • 首选<tx:annotation-driven />@Transactional - 仅在服务层上
  • 事务管理器还打开和关闭会话(如果线程中不存在会话)。很高兴知道会话是每个请求的会话。每个请求(=线程)都有一个单独的会话实例。但是只有在需要时才会创建数据库连接,因此即使所有方法周围都有事务管理器,也不会打开不必要的连接。
  • 只读事务 - 在只有数据检索的情况下使用 @Transactional(readOnly=true)
  • 缓存 - 利用休眠二级缓存将实体放入内存(而不是每次都从数据库中获取)
  • 避免OpenSessionInView 和惰性集合。这是主观的,但在我看来,所有离开服务层的对象都必须被初始化。对于小型集合(例如角色列表),您可以拥有急切的集合。对于更大的集合,请使用 HQL 查询。

【讨论】:

  • 我同意这是标准的。如果我们在使用 EntityManager 的性能或资源利用方面有任何其他优势,请您区分一下。另外,如果我们想支持 DB 表的水平分区,推荐的技术是什么?
  • 相同。如果您真的最终需要原始休眠会话甚至连接,您可以通过entityManager.unwrap(Session.class) 获得它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 2010-10-06
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多