2024年3月14日发(作者:)

开发人员、设计人员和架构师经常会混淆

事务模型

事务策略

。我经常会让与

客户接触的架构师和技术总监描述他们项目的事务策略。我通常会获得三种回应。

有时,他们会说 “我们实际上并未在应用程序中使用事务。”另一些时候,我

会听到迷惑的回答:“我不明白你的意思。”但是,我也会遇到非常自信的回答:

“我们使用声明式事务。”在本文中,术语

声明式事务

描述的是一个事务

模型

但它绝不是一种事务

策略

关于本系列

事务将改善您数据的质量、完整性以及一致性,并且让您的应用程序更加可靠。

在 Java 应用程序中实现成功的事务处理并不是一项轻松的任务,它是一项与编

写代码相关的设计工作。 在这个新的 系列 中,Mark Richards 将指导您设计

一个有效的事务策略,它适用于各种用例,从简单的应用程序到高级性能事务处

理。

Java 平台支持的三种事务模型包括:

Local Transaction 模型

Programmatic Transaction 模型

Declarative Transaction 模型

这些模型描述事务在 Java 平台中的基本运行方式,以及它们是如何实现的。但

是,它们仅提供了事务处理的规则和语义。如何应用事务模型则完全由您决定。

举例来说,应该如何在 REQUIRED 和 MANDATORY 事务属性之间做出选择?您应

该在何时何种情况下指定事务回滚指令?您应该在何时考虑 Programmatic

Transaction 模型与 Declarative Transaction 模型的优劣?您应该如何优化

高性能系统的事务?事务模型本身无法回答这些问题。您必须通过开发自己的事

务策略或采用本文介绍的四种主要事务策略之一来解决它们。

如本系列的 第一篇文章 所述,许多常见的事务陷阱都会影响到事务行为,并且

由此会降低数据的完整性和一致性。同样,缺乏有效的(或任何)事务策略将对

您数据的完整性和一致性造成负面影响。本文所描述的事务模型是开发有效事务

策略的基本元素。理解这些模型之间的差异以及它们的运行方式对于理解使用它

们的事务策略非常重要。在介绍完三种事务模型之后,我将讨论适用于大多数业

务应用程序(从简单的 Web 应用程序到大型的高速事务处理系统)的四种事务

策略。

事务策略

系列的后续文章将详细讨论这些策略。

Local Transaction 模型

在 Local Transaction 模型中,事务由底层数据库资源管理程序(而非应用程

序所在的容器或框架)管理,这便是它得名的原因。在这个模型中,您将管理

,而不是

事务

。从 “了解事务陷阱” 一文可知,在使用对象关系映射框架,

如 Hibernate、TopLink 或 the Java Persistence API (JPA),执行数据库更

新时,您不能使用 Local Transaction 模型。在使用数据访问对象(DAO)或基

于 JDBC 的框架和数据库存储过程时,您可以使用它。

您可以采用以下两种方式来使用 Local Transaction 模型:让数据库来管理连

接,或者以编程的方式管理连接。要让数据库管理连接,您需要将 JDBC

Connection 对象上的 autoCommit 属性设置为 true(默认值),这将通知底层

数据库管理系统(DBMS)在完成插入、更新或删除操作之后提交事务,或者在操

作失败时返回任务。清单 1 展示了这种技巧,它在 TRADE 表中插入了一条股票

交易命令:

清单 1. 包括一个更新的本地事务

public class TradingServiceImpl {

public void processTrade(TradeData trade) throws Exception {

Connection dbConnection = null;

try {

DataSource ds = (DataSource)

(new InitialContext()).lookup("jdbc/MasterDS");

dbConnection = nection();

oCommit(true);

Statement sql = Statement();

String stmt = "insert into TRADE ...";

eUpdate(stmt1);

} finally {

if (dbConnection != null)

();

}

}

}

注意,在清单 1 中,autoCommit 值设置为 true,这将指示 DBMS 应该在各数

据库语句之后提交本地事务。如果在逻辑工作单元(LUW)中维护一个数据库活

动,那么这一技巧将非常有用。但是,假设清单 1 中的 processTrade() 方法

还将更新 ACCT 表中的余额以反映交易订单的值。在本例中,两个数据库操作是

相互独立的,针对 TRADE 表的插入操作将在更新 ACCT 表之后提交给数据库。

若 ACCT 表更新失败,没有任何机制可以回滚到对 TRADE 表的更新操作,从而

造成数据库中的数据不一致。

此场景又引出了第二个技巧:以编程的方式管理连接。在此技巧中,您将

Connection 对象上的 autoCommit 属性设置为 false,并手动提交或回滚连接。

清单 2 演示了此技巧: