将Session对象注入DAO bean而不是Session Factory?

时间:2013-05-31 02:37:12

标签: spring hibernate

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

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

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

我认为第一种方法是正确的但是在寻找第二种方法会抛出错误或可能性能不佳的具体情况?

2 个答案:

答案 0 :(得分:3)

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

对于大多数情况,会话应该是事务范围,即,在事务开始时打开新会话,然后在事务结束后自动关闭。在少数情况下,可能需要扩展到请求范围。

如果你想避免使用SessionFactory.currentSession,那么你需要定义自己的范围实现来实现它。

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

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

答案 1 :(得分:3)

注入原型会话意味着根据定义,每个DAO对象都会获得自己的会话...另一方面,SessionFactoryopen提供权限并随意共享会话。

实际上getCurrentSession不会在每次调用时打开一个新的Session ...相反,它会重用绑定到current session context的会话(例如,Thread,JTA Transacion或Externally Managed context)。 / p>

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

  1. 跨越多个会话,每个会话管理自己的对象并绑定到不同的交易。
  2. 管理与此操作相关的对象的单个会话...根据您的业务需求划分交易。
  3. 简而言之,有效地共享会话和划分事务不仅可以提高应用程序性能,还可以作为应用程序功能的一部分。

    我强烈建议您阅读Chapter 2Chapter 13Hibernate Core Reference Manual,以便更好地了解SessionFactorySession和{{1}的角色在框架内播放。它还将教授关于工作单元以及流行的会话模式和反模式的意愿。