5

在我们的应用程序中,我们使用 Spring 和 Hibernate。

在所有 DAO 类中,我们都有 SessionFactory 自动连接,并且每个 DAO 方法都调用 getCurrentSession() 方法。

我的问题是为什么我们不在原型范围内注入 Session 对象而不是 SessionFactory 对象?这将为我们节省对 getCurrentSession 的调用。

我认为第一种方法是正确的,但是寻找第二种方法会引发错误或性能不佳的具体场景?

4

2 回答 2

3

当您将 bean 定义为原型作用域时,会为每个需要注入它的位置创建一个新实例。所以每个 DAO 都会得到一个不同的 Session 实例,但是 DAO 上的所有方法调用最终都会使用同一个 session。由于会话不是线程安全的,因此不应在多个线程之间共享,这将是一个问题。

在大多数情况下,会话应该是事务范围,即在事务开始时打开一个新会话,然后在事务完成后自动关闭。在少数情况下,它可能必须扩展到请求范围。

如果您想避免使用 SessionFactory.currentSession - 那么您将需要定义自己的范围实现来实现这一点。

这是已经使用代理为 JPA 实现的东西。在 JPA 的情况下,注入的是 EntityManager 而不是 EntityManagerFactory。代替 @Autowired 有一个新的 @PersistenceContext 注释。在初始化期间创建并注入代理。当调用任何方法时,代理将获取实际的 EntityManager 实现(使用类似于 SessionFactory.getCurrentSession 的东西)并委托给它。

类似的事情也可以为 Hibernate 实现,但额外的复杂性是不值得的。在内部调用 SessionFactory.getCurrentSession() 的 BaseDAO 中定义 getSession 方法要简单得多。这样,使用会话的代码与注入会话相同。

于 2013-05-31T04:08:57.033 回答
3

注入原型会话意味着您的每个 DAO 对象都将根据定义获得自己的会话……另一方面SessionFactory,您可以随意打开和共享会话。

事实上, getCurrentSession不会在每次调用时打开一个新的会话……相反,它会重用绑定到当前会话上下文(例如,线程、JTA 事务或外部管理上下文)的会话。

所以让我们考虑一下;假设在您的业务层中有一个操作需要读取和更新多个数据库表(这意味着直接或间接地与多个 DAO 进行交互)......很常见的场景对吧?通常,当这种操作失败时,您会想要回滚当前操作中发生的所有事情,对吗?那么,对于这种“特殊”情况,什么样的策略似乎合适呢?

  1. 跨越多个会话,每个会话管理自己类型的对象并绑定到不同的事务。
  2. 有一个单独的会话来管理与此操作相关的对象...根据您的业务需求划分事务。

简而言之,有效地共享会话和划分事务不仅会提高您的应用程序性能,它还是您的应用程序功能的一部分。

我强烈建议您阅读Hibernate Core 参考手册第 2章和第 13 章,以更好地理解框架中的角色和角色。它还将教授有关工作单元以及流行的会话模式和反模式的意愿。SessionFactorySessionTransaction

于 2013-05-31T04:50:13.690 回答