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

Bra*_*ugh 5 spring hibernate

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

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

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

Thi*_*rry 1

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

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

方案二:业务层事务边界

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

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

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


无论如何,如果您希望保持事务简短,我建议您仔细观察每个业务用例的“sql 足迹”(通过将 org.hibernate.SQL 日志类别设置为 DEBUG)并将生成的 sql 与生成的 sql 进行比较你会自己写的。

大多数时候我看到缓慢的用例,这是因为 hibernate 延迟加载功能没有正确配置(它要么太急切,在每个查询中添加十二个级别的连接,要么太懒,按集合元素发出查询)