ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 11.1.2\. 长对话 session-per-request模式不仅仅是一个可以用来设计操作单元的有用概念。很多业务处理都需 要一系列完整的与用户之间的交互,而这些用户是指对数据库有交叉访问的用户。在基于web的应用和企业 应用中,跨用户交互的数据库事务是无法接受的。考虑下面的例子: * 在界面的第一屏,打开对话框,用户所看到的数据是被一个特定的 `Session` 和数据 库事务载入(load)的。用户可以随意修改对话框中的数据对象。 * 5分钟后,用户点击“保存”,期望所做出的修改被持久化;同时他也期望自己是唯一修改这个信息的人,不会出现 修改冲突。 从用户的角度来看,我们把这个操作单元称为长时间运行的_对话_(conversation),或者(or _应用事务_,application transaction)。 在你的应用程序中,可以有很多种方法来实现它。 头一个幼稚的做法是,在用户思考的过程中,保持`Session`和数据库事务是打开的, 保持数据库锁定,以阻止并发修改,从而保证数据库事务隔离级别和原子操作。这种方式当然是一个反模式, 因为锁争用会导致应用程序无法扩展并发用户的数目。 很明显,我们必须使用多个数据库事务来实现这个对话。在这个例子中,维护业务处理的 事务隔离变成了应用程序层的部分责任。一个对话通常跨越多个数据库事务。如果仅仅只有一 个数据库事务(最后的那个事务)保存更新过的数据,而所有其他事务只是单纯的读取数据(例如在一 个跨越多个请求/响应周期的向导风格的对话框中),那么应用程序事务将保证其原子性。这种方式比听 起来还要容易实现,特别是当你使用了Hibernate的下述特性的时候: * _自动版本化_ - Hibernate能够自动进行乐观并发控制 ,如果在用户思考 的过程中发生并发修改,Hibernate能够自动检测到。一般我们只在对话结束时才检查。 * _脱管对象_(Detached Objects)- 如果你决定采用前面已经讨论过的 _session-per-request_模式,所有载入的实例在用户思考的过程 中都处于与Session脱离的状态。Hibernate允许你把与Session脱离的对象重新关联到Session 上,并且对修改进行持久化,这种模式被称为 _session-per-request-with-detached-objects_。自动版本化被用来隔离并发修改。 * _Extended (or Long) Session_ - Hibernate 的`Session` 可以在数据库事务提交之后和底层的JDBC连接断开,当一个新的客户端请求到来的时候,它又重新连接上底层的 JDBC连接。这种模式被称之为_session-per-conversation_,这种情况可 能会造成不必要的Session和JDBC连接的重新关联。自动版本化被用来隔离并发修改, `Session`通常不允许自动flush,而是明确flush。 _session-per-request-with-detached-objects_ 和 _session-per-conversation_ 各有优缺点,我们在本章后面乐观并发 控制那部分再进行讨论。