在Spring / Hibernate堆栈中打开会话的位置?

时间:2010-05-19 07:29:25

标签: hibernate spring

我正在尝试为Spring / Hibernate应用程序找到一个好的设计。在创建这样的应用程序时,似乎有一些重大决定。

第一个主要决定似乎是放置会话/事务边界的位置。看起来我有三个主要选择:作为控制器甚至调用之前的过滤器,紧接在服务调用级别的控制器之下,并且在存储库调用中的业务级别之下填充。

在我看来,正确的呼叫是中间路径,但我不确定。我不希望我的事务打开太长时间,但同时,我不想经常担心业务逻辑中的分离对象和延迟加载。不过,还有一些缺点。例如,它使业务逻辑很难在没有暂停事务几秒钟的情况下进行远程调用。我想知道是否有更好的方法?

2 个答案:

答案 0 :(得分:1)

这取决于你如何模块化代码。我假设您没有在控制器中编写所有与数据库事务相关的代码。如果您已将代码分离到处理事务的DAO或服务层,那么只有所需的粒度才有意义。

长时间保持交易占用并不是一个好的设计,因此让过滤器打开会话可能是一个坏主意。除非,您有一些您希望打开会话的延迟加载对象。

如果上述内容不适用,那么您只能在数据访问层周围设置事务/会话边界。

答案 1 :(得分:1)

解决方案1:在视图过滤器中打开会话

  • 优点:
    • 您不会遇到延迟初始化异常,因此您可以在视图中使用模型对象而无需考虑三次
    • 如果您进行多次服务呼叫,您将不必担心您的控制器在不同的交易中工作(如果在第二次服务呼叫期间发生错误,您的第一次呼叫将不会被回滚)。
  • 缺点:
    • 更长的交易
    • 如果在提交时发生错误(例如,数据约束违规),您将在视图的大部分时间内写入响应输出流,因此您将无法显示错误页面(除非您使用上面的其他过滤器) “在视图中打开会话”一个将存储outstream直到提交完成,然后才将生成的页面发送到客户端或重定向到错误页面)

解决方案2:业务层的事务边界

  • 优点:
    • 在控制器级别具有更大的灵活性(但如果您的团队成员并不真正理解事务,并且在控制器级别放置太多逻辑,使用多个tx,那么这可能是一个诅咒,应该只有一个)
    • 减少资源使用(当您更快地将数据库连接回池时)
  • 缺点:
    • 在交易层之外,您需要仔细使用模型的对象。避免lazyInitialization异常的最简单方法可能是使用DTO,并让每个服务实现两个接口(一个扩展另一个):一个只包含返回DTO的方法,另一个只返回模型返回对象的方法。您将在控制器中的声明中使用第一个接口,并仅在业务层中使用第二个接口,其中事务仍处于打开状态,因此返回模型对象不会导致延迟初始化异常。

解决方案3:dao层的事务边界

除非您的dao方法包含业务逻辑,否则将事务限制为dao调用是没有意义的。这就是接近“自动提交”模式的方式,我觉得这很有用。


在任何情况下,如果您希望保持简短的交易,我建议您密切关注每个业务用例的“sql足迹”(通过将org.hibernate.SQL日志类别设置为DEBUG)并比较生成的sql你自己写的东西。

大多数时候我看到慢用例,这是因为hibernate延迟加载功能没有正确配置(它太急切了,在每个查询中添加了12个级别的连接,或者太懒,发出查询收藏元素)