Welcome 微信登录

首页 / 软件开发 / JAVA / Spring Web Flow 2中流管理的持久化:事务性Web流的持久化策略

Spring Web Flow 2中流管理的持久化:事务性Web流的持久化策略2012-02-26 IBM Xinyu LiuSpring Web Flow 是一种新颖的 Java™ Web 框架,它扩展了 Spring MVC 技术。使用 Spring Web Flow 的应用开发围绕着定义为 Web 流的用例展开。 将开发工作区根据 Web 流进行组织使开发体验更有意义、更具上下文。此外,Spring Web Flow 对 JPA/Hibernate 持久化的支持也是其最重要的服务器端改进之一。

尽管 SpringSource 和 Spring Web Flow 项目组详细介绍了 Spring Web Flow,但是其持久化支持,尤其是其流管理的持久化机制,很少为人所了解。本文将深入介绍 Spring Web Flow 2 中的 Java 持久化编程,重点讲解流管理的持久化及其基本组件 — 流作用域的持久化上下文。

在概述 Spring Web Flow 持久化的基本概念之后,我将呈现几个用例,为大家展示处理原子和非原子 Web 流中的只读和读/写事务的策略。在每种情况下,我都将解释首选事务处理策略的基本思想并说明其缺点。本文结尾我为大家总结了在 Spring Web Flow 2 中高效、安全地管理事务的一些指导原则。

本文面向熟悉 Spring Web Flow 2 及其基于 continuations 的架构的经验丰富的 Java 开发人员。已经在 Spring Web Flow 中使用 JPA/Hibernate 的开发人员将从用例和样例应用程序代码中受益良多。

JPA/Hibernate 中的持久化挑战

在典型的 Web 应用程序中,有两个主要步骤处理用户请求:操作处理和视图呈现。应用程序的主要业务逻辑驻留在操作处理中。随后进行的视图呈现将数据提供给视图模板,将视图展现出来。

在 JPA/Hibernate 中,数据(更确切地说是实体关系)可能急切加载或延迟加载为代理对象。如果持久化上下文对象(JPA EntityManager 或 Hibernate Session)在视图呈现阶段已经关闭,那么实体就会分离。任何访问分离实体上已卸载的关系的尝试都将导致 LazyInitializationException 异常。

Open Session in View 模式试图解决 LazyInitializationException 异常。当 Open Session in View 模式作为过滤器或拦截器实现时,持久化上下文对象在视图呈现期间会保持打开状态。导航到持久实体上的已卸载关系将触发其他的数据库查询来按需获取关系。

Open Session in View 模式的一个缺点是持久化上下文对象被高效地划定到用户请求作用域内。因此,存储在 Servlet 作用域中的实体,除当前请求外,总是被分离。分离的实体需要合并/重新连接/重新加载操作才能与当前持久化上下文关联。

Spring Web Flow 采用了不同的方法,它通过流管理的持久化,更确切地说是流作用域的持久化上下文对象,解决了分离实体状态的问题。

流管理的持久化

Spring Web Flow 中的应用程序开发基于 Web 流 的概念,Web 流通常代表一个单独的用例。在很多情况中,整个 Web 流中的数据变化需要是 原子的,也就是说流不同阶段的变化或者作为整体被保存到后端数据库中,或者全部取消,在数据库中不留下任何痕迹。

Spring Web Flow 通过流管理的持久化 机制简化了事务性原子 Web 流中的 JPA/Hibernate 编程。流管理的持久化在概念上与 Hibernate/Seam 对话一样,其中在 Web 流(或者 Seam 中的 “页面流”)期间进行的数据变更都作为脏实体缓存在同一个流作用域的持久化上下文对象中。直到流结束时才会激活 SQL insert/update/delete 语句,将变更一次刷新并提交到数据库中。(注意,“刷新” 和 “提交” 是不同的概念;前者激活一系列 SQL insert/update/delete 语句使脏实体与其相应数据库值同步,而后者只是提交数据库事务)。

流管理持久化中的 OptimisticLockingFailureException

乐观锁 是一个极其有效的并发性控制方法,它可以确保数据完整性而又无需在数据库中放置任何物理锁。尽管不是强制实施的,但是强烈建议在流管理的持久化中使用乐观锁。

持久化上下文在刷新时检查实体版本,如果检查出并发的修改,它就抛出 OptimisticLockingFailureException 异常(在 Hibernate 中是 StaleObjectException 异常)。实体在内存中存在的时间越长,其对应的数据库值被其他进程修改的可能性越大。

如上所述,在 Open Session in View 模式中,实体的持久状态受制于用户请求。一旦实体分离,通常需要在后续用户请求中进行合并/重新连接/重新加载操作来还原实体的持久状态,从而使实体与其对应的数据库值保持同步。

在流管理的持久化中,实体在多个用户请求之间保存其持久状态。在各用户请求之间没有强制执行数据库同步,因此很有可能出现 OptimisticLockingFailureException 异常。重要的是要优雅地处理 OptimisticLockingFailureException 异常,就像处理任何检查型业务异常一样。(即使 OptimisticLockingFailureException 是一个回滚到数据库事务的运行时异常,也应如此)。常用的策略是让用户有机会合并其变更或用未过期数据重启流。