- 浏览: 344591 次
- 性别:
- 来自: 南京
-
文章分类
最新评论
-
lixuejian:
Nice.[align=center][/align]
数据库范式概念解析(第一范式,第二范式,第三范式) -
静夜独窗:
正需要,好代码
详解JAVA POI导出EXCEL报表的操作(包括各种格式及样式的实现) -
youlomg:
[color=olive][color=gray][color ...
详解JAVA POI导出EXCEL报表的操作(包括各种格式及样式的实现) -
zhuliuwu:
文档虽然不错,但函数的解释用法有歧义。切记切记,例如match ...
AWK命令详解(大全) -
softwareengineer:
赞一个,很容易理解。
数据库范式概念解析(第一范式,第二范式,第三范式)
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 = ds.getConnection();
dbConnection.setAutoCommit(true);
Statement sql = dbConnection.createStatement();
String stmt = "insert into TRADE ...";
sql.executeUpdate(stmt1);
} finally {
if (dbConnection != null)
dbConnection.close();
}
}
}
注意,在清单 1 中,autoCommit 值设置为 true,这将指示 DBMS 应该在各数据库语句之后提交本地事务。如果在逻辑工作单元(LUW)中维护一个数据库活动,那么这一技巧将非常有用。但是,假设清单 1 中的 processTrade() 方法还将更新 ACCT 表中的余额以反映交易订单的值。在本例中,两个数据库操作是相互独立的,针对 TRADE 表的插入操作将在更新 ACCT 表之后提交给数据库。若 ACCT 表更新失败,没有任何机制可以回滚到对 TRADE 表的更新操作,从而造成数据库中的数据不一致。
此场景又引出了第二个技巧:以编程的方式管理连接。在此技巧中,您将 Connection 对象上的 autoCommit 属性设置为 false,并手动提交或回滚连接。清单 2 演示了此技巧:
清单 2. 包括多个更新的本地事务
public class TradingServiceImpl {
public void processTrade(TradeData trade) throws Exception {
Connection dbConnection = null;
try {
DataSource ds = (DataSource)
(new InitialContext()).lookup("jdbc/MasterDS");
dbConnection = ds.getConnection();
dbConnection.setAutoCommit(false);
Statement sql = dbConnection.createStatement();
String stmt1 = "insert into TRADE ...";
sql.executeUpdate(stmt1);
String stmt2 = "update ACCT set balance...";
sql.executeUpdate(stmt2);
dbConnection.commit();
} catch (Exception up) {
dbConnection.rollback();
throw up;
} finally {
if (dbConnection != null)
dbConnection.close();
}
}
}
注意,在清单 2 中,autoCommit 属性设置为 false,这将通知底层 DBMS 在代码而非数据库中管理连接。在本例中,如果一切正常,您必须调用 Connection 对象上的 commit() 方法;否则,如果出现异常,则调用 rollback() 方法。通过这种方式,您可以在相同的工作单元中协调两个数据库活动。
虽然 Local Transaction 模型现在看来有些过时,但它是本文结束部分介绍的一个主要事务策略的重要元素。
Programmatic Transaction 模型
Programmatic Transaction 模型的名称来自这样一个事实:开发人负责管理事务。在 Programmatic Transaction 模型中,与 Local Transaction 模型不同,您将管理事务,并且将与底层数据库连接 相分离。
与 清单 2 中的示例相似,借助此模型,开发人员将负责从事务管理程序获取一个事务,启动该事务,提交事务,以及(如果出现异常)回滚到事务。您可能已经猜到,这会产生大量易于出错的代码,从而对应用程序中的业务逻辑造成影响。但是,一些事务策略需要使用 Programmatic Transaction 模型。
虽然概念是相同的是,但 Programmatic Transaction 模型的实现在 Spring Framework 和 EJB 3.0 规范中是不同的。我将先使用 EJB 3.0 来演示这个模型的实现,然后使用 Spring Framework 来展示相同的数据库更新。
使用 EJB 3.0 实现编程事务
在 EJB 3.0 中,您将从事务管理程序(换句话说,容器)获取一个事务,方法是对 javax.transaction.UserTransaction 执行 Java Naming and Directory Interface (JNDI) 查找。获取 UserTransaction 之后,您可以调用 begin() 方法来启动事务,调用 commit() 方法来提交事务,并且调用 rollback() 方法以便在出现错误时回滚事务。在此模型中,容器不会自动提交或回滚事务;开发人员需要自己在执行数据库更新的方法编写此行为。清单 3 通过 JPA 展示了使用 EJB 3.0 的 Programmatic Transaction 模型:
清单 3. 使用 EJB 3.0 实现的编程事务
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class TradingServiceImpl implements TradingService {
@PersistenceContext(unitName="trading") EntityManager em;
public void processTrade(TradeData trade) throws Exception {
InitialContext ctx = new InitialContext();
UserTransaction txn = (UserTransaction)ctx.lookup("UserTransaction");
try {
txn.begin();
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
txn.commit();
} catch (Exception up) {
txn.rollback();
throw up;
}
}
}
在带无状态会话 bean 的 Java EE 容器环境中使用 Programmatic Transaction 模型时,您必须通知容器您正在使用编程事务。为此,您需要使用 @TransactionManagement 注释并将事务类型设置为 BEAN。如果您未使用此注释,则容器将假定您使用声明式事务管理(CONTAINER),它是 EJB 3.0 的默认事务类型。在无状态会话 bean 上下文外部的客户机层中使用编程事务时,您不需要设置事务类型。
使用 Spring 实现编程事务
Spring Framework 提供了两种实现 Programmatic Transaction 模型的方法。一种是通过 Spring TransactionTemplate 来实现,另一种是直接使用 Spring 平台事务管理程序。由于我并不热衷于编写匿名内部类和难以理解的代码,因此我将使用第二种技巧来演示 Spring 中的 Programmatic Transaction 模型。
Spring 至少有九种平台事务管理程序。最常用的包括 DataSourceTransactionManager、HibernateTransactionManager、JpaTransactionManager 和 JtaTransactionManager。我的代码示例使用的是 JPA,因此我将展示 JpaTransactionManager 的配置。
要在 Spring 中配置 JpaTransactionManager,只需要使用 org.springframework.orm.jpa.JpaTransactionManager 类在应用程序上下文 XML 文件中定义 bean,并添加一个到 JPA Entity Manager Factory bean 的引用。然后,假定包含应用程序逻辑的类是由 Spring 管理的,将事务管理程序注入到 bean 中,如清单 4 所示:
清单 4. 定义 Spring JPA 事务管理程序
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="tradingService" class="com.trading.service.TradingServiceImpl">
<property name="txnManager" ref="transactionManager"/>
</bean>
如果 Spring 未管理应用程序类,那么您可以在您的方法中引用事务管理程序,方法是在 Spring 上下文中使用 getBean() 方法。
在源代码中,您现在可以使用平台管理程序获取一个事务。执行了所有更新之后,您可以调用 commit() 方法来提交事务,或者调用 rollback() 方法来回滚事务。清单 5 展示了此技巧:
清单 5. 使用 Spring JPA 事务管理程序
public class TradingServiceImpl {
@PersistenceContext(unitName="trading") EntityManager em;
JpaTransactionManager txnManager = null;
public void setTxnManager(JpaTransactionManager mgr) {
txnManager = mgr;
}
public void processTrade(TradeData trade) throws Exception {
TransactionStatus status =
txnManager.getTransaction(new DefaultTransactionDefinition());
try {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
txnManager.commit(status);
} catch (Exception up) {
txnManager.rollback(status);
throw up;
}
}
}
注意清单 5 中 Spring Framework 与 EJB 3.0 之间的差异。在 Spring 中,获取事务(随后启动它)的方法是在平台事务管理程序上调用 getTransaction()。匿名 DefaultTransactionDefinition 类包含关于事务及其行为的详细信息,包括事务名称、隔离级别、传播模式(事务属性)和事务超时(如果存在)。在本例中,我可以仅使用默认值,其名称是空字符串,底层 DBMS 的默认的隔离级别通常为 READ_COMMITTED,事务属性是 PROPAGATION_REQUIRED,以及 DBMS 的默认超时。还需注意,commit() 和 rollback() 方法是使用平台事务管理程序调用的,而不是事务(与 DJB 的情况相同)。
Declarative Transaction 模型
Declarative Transaction 模型,又称作 Container Managed Transactions (CMT),是 Java 平台中最常用的事务模型。在该模型中,容器环境负责启动、提交和回滚事务。开发人员仅负责指定事务的行为。本系列的 第一篇文章 所讨论的大多数事务陷阱都与 Declarative Transaction 模型相关。
Spring Framework 和 EJB 3.0 都利用注释来指定事务行为。Spring 使用 @Transactional 注释,而 EJB 3.0 使用 @TransactionAttribute 注释。在使用 Declarative Transaction 模型时,容器将不会针对检测到的异常自动回滚事务。开发人员必须指定出现异常时在何处以及何时回滚事务。在 Spring Framework 中,您通过使用 @Transactional 注释上的 rollbackFor 属性来指定它。在 EJB 中,您通过调用 SessionContext 上的 setRollbackOnly() 方法来指定它。
清单 6 展示了 Declarative Transaction 模型的 EJB 应用:
清单 6. 使用 EJB 3.0 的声明式事务
@Stateless
public class TradingServiceImpl implements TradingService {
@PersistenceContext(unitName="trading") EntityManager em;
@Resource SessionContext ctx;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void processTrade(TradeData trade) throws Exception {
try {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
} catch (Exception up) {
ctx.setRollbackOnly();
throw up;
}
}
}
清单 7 演示了 Declarative Transaction 模型的 Spring Framework 应用:
清单 7. 使用 Spring 的声明式事务
public class TradingServiceImpl {
@PersistenceContext(unitName="trading") EntityManager em;
@Transactional(propagation=Propagation.REQUIRED,
rollbackFor=Exception.class)
public void processTrade(TradeData trade) throws Exception {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
}
}
事务属性
除了回滚指令之外,您还必须指定事务属性,这将定义事务的行为。Java 平台支持六种事务属性,而与您使用的是 EJB 还是 Spring Framework 无关:
* Required
* Mandatory
* RequiresNew
* Supports
* NotSupported
* Never
在描述这些事务属性时,我将使用一个假想的 methodA() 方法,事务属性将应用于这个方法。
如果为 methodA() 指定了 Required 事务属性,并且在已有事务作用域内调用了 methodA(),那么将使用已有的事务作用域。否则,methodA() 将启动一个新的事务。如果事务是由 methodA() 启动的,则它也必须由 methodA() 来终止(提交或回滚)。这是最常用的事务属性,并且是 EJB 3.0 和 Spring 的默认属性。遗憾的是,它的使用并不正确,从而造成了数据完整性和一致性问题。对于本系列后续文章将要讨论的各事务策略,我将更加详细地阐述这个事务属性。
如果为 methodA() 指定了 Mandatory 事务属性,并且在已有事务作用域内调用了 methodA(),那么将使用已有的事务作用域。但是,如果调用 methodA() 时没有事务上下文,则会抛出一个 TransactionRequiredException,指示必须在调用 methodA() 之前呈现事务。这个事务属性应用于本文下一部分将要讨论的 Client Orchestration 事务策略。
RequiresNew 事务属性非常有趣。许多时候,我会发现这个属性被误用或误解。methodA() 指定了 RequiresNew 属性,并且在有或没有事务上下文的情况下调用了 methodA(),那么新事务将始终由 methodA() 启动(和终止)。这意味着,如果在另一个事务(比如说 Transaction1)的上下文中调用了 methodA(),那么 Transaction1 将暂停,同时会启动一个新的事务(Transaction2)。当 methodA() 结束时,Transaction2 将提交或回滚,并且 Transaction1 将恢复。这显然违背了事务的 ACID(atomicity、consistency、isolation 和 durability)属性(特别是 atomicity 属性)。换句话说,所有数据库更新都不再包含在一个单一的工作单元中。如果 Transaction1 将进行回滚,则由 Transaction2 提交的更改将仍然被提交。如果是这种情况,那么事务属性有什么好处呢?如本系列第一篇文章所述,这个事务属性仅用于独立于底层事务的数据库操作(比如审计或记录,在本例中为 Transaction1)。
Supports 事务属性也是我发现大多数开发人员未完全理解或掌握的一个地方。如果为 methodA() 指定了 Supports 事务属性,并且在已有事务的作用域中调用了 methodA(),则 methodA() 将在该事务的作用域中执行。但是,如果在没有事务上下文的情况下调用了 methodA(),则不会启动任何事务。此属性主要用于针对数据库的只读操作。如果是这种情况,为何不指定 NotSupported 事务属性(在下一段中讨论)呢?毕竟,该属性将确保方法在没有事务的情况下运行。答案非常简单。在已有事务的上下文中调用查询操作会导致从数据库事务日志中读取数据(换句话说,已更新的数据),而不在事务作用域中运行会导致查询从表中读取未修改的数据。举例来说,如果您插入一个新的交易订单到 TRADE 表中,然后(在相同的事务中)获取所有交易订单的列表,则未提交的交易将出现在列表中。但是,如果您使用的是 NotSupported 事务属性,那么它会造成数据库查询从表中而不是从事务日志中读取数据。因此,在上一个示例中,您将不会看到未提交的交易。这并不一定是一件坏事;这将由您的用例和业务逻辑决定。
NotSupported 事务属性指定被调用的方法将不使用或启动事务,无论是否呈现了事务。如果为 methodA() 指定了 NotSupported 事务属性,并且在某个事务的上下文中调用了 methodA(),则该事务将暂停直到 methodA() 结束。当 methodA() 结束时,原始事务将被恢复。这个事务属性只有少许用例,并且它们主要涉及数据库存储过程。如果您尝试在已有事务上下文的作用域中调用数据库存储过程,并且数据库存储过程包含一个 BEGIN TRANS,或者对于 Sybase 的情况,在未连接模式中运行,则会抛出一个异常,指示已经存在一个事务无法启动新事务。(换句话说,内嵌事务不受支持)。几乎所有的容器都使用 Java Transaction Service (JTS) 作为默认的 JTA 事务实现。不支持内嵌事务的是 JTS 而不是 Java 平台。如果您无法修改数据库存储过程,那么您可以使用 NotSupported 属性来暂停已有事务上下文,以避免这种致命的异常。但是,其影响是您不能在相同的 LUW 中对数据库执行原子更新。这是一种权衡,但有时可以让您迅速脱离困境。
Never 或许是最有趣的事务属性。它的行为类似于 NotSupported 事务属性,但存在一个重要差异:如果使用 Never 事务属性调用方法时已经存在某个事务上下文,则会抛出一个异常,指示您在调用该方法时不允许使用这个事务。我能想到的针对此事务属性的唯一一个用例就是用于测试。它提供了一种简单的方法,用于验证当您调用特定的方法时某个事务是否存在。如果您在调用相应的方法时使用了 Never 事务属性并且接收到了一个异常,则知道事务已经呈现。如果允许执行方法,则您知道事务未被呈现。这是确保事务策略坚固的理想方法。
事务策略
本文描述的事务模型形成了即将介绍的事务策略的基础。在开始构建事务策略之前,完全理解这些模型之间的差异以及它们的运行原理是非常重要的。可以在大多数业务应用程序场景中使用的主要事务策略包括:
* Client Orchestration 事务策略
* API Layer 事务策略
* High Concurrency 事务策略
* High-Speed Processing 事务策略
我将在此处简要介绍这些策略,并将在本系列的后续文章中详细讨论它们。
当来自客户机层的基于多服务器或基于模型的调用完成单一工作单元时,将使用 Client Orchestration 事务策略。此处的客户机层可以表示来自 Web 框架、门户应用程序、桌面系统或工作流产品或业务流程管理(BPM)组件的调用。从本质上说,客户机层拥有处理流以及完成特定请求所需的 “步骤”。举例来说,要添加一个交易订单,假定您需要将交易插入到数据库中,然后更新客户的帐户余额以反映交易的值。如果应用程序的 API 层非常细粒度化,那么您需要调用客户机层中的两个方法。在此场景中,事务工作单元必须位于客户机层中以确保自动化的工作单元。
当粗粒度方法充当后端功能的主要入口点时,将使用 API Layer 事务策略。(如果愿意,可以将它们称作 services)。在此场景中,客户机(基于 Web、基于 Web 服务、基于消息或者甚至桌面)向后端发起单个调用以执行特定的请求。使用上文提到的交易订单场景,在本例中您将拥有一个入口点方法(比如说 processTrade())由客户机层调用。然后,这个方法将包含插入交易订单和更新帐户所需的业务流程。我将这个策略指定为这个名称的原因是,在大多数情况下,后端处理功能会通过使用接口或 API 向客户应用程序公开。这是最常用的事务策略之一。
High Concurrency 事务策略是 API Layer 事务策略的一个变体,它用于不支持通过 API 层长时间运行事务的应用程序(通常出于性能或可伸缩性需求的原因)。顾名思义,此策略主要在从用户的角度支持高度并发性的应用程序中使用。事务在 Java 平台的开销非常大。根据您所使用的数据库,它们可以造成在数据库中出现锁定,独占资源,在吞吐量方面拖慢应用程序,并且在某些情况下甚至造成数据库死锁。这种事务策略内部的主要思想是缩短事务作用域,以便您能够最大限度地减少数据库中的死锁,同时仍然为任何特定的客户机请求维持自动工作单元。在某些情况下,您可能需要重构应用程序逻辑,以支持这种事务策略。
High-Speed Processing 事务策略或许是事务策略的最极端。如果您需要从应用程序中获取最快的处理时间(以及吞吐量),并且仍然在处理中维持一定程序的事务原子性,那么可以使用它。虽然这种策略从数据完整性和一致的角度来说引入了一些风险,但如果正确实现,它将成为 Java 平台中速度可能是最快的事务策略。它可能是这四个事务策略中最难以实现的一个。
结束语
从这篇概述中可以看到,开发一个有效的事务策略并非总是一项简单的任务。在解决数据完整性和一致问题时需要考虑各种事项、选项、模型、框架、配置和技巧。在使用应用程序和事务的多年经验中,我发现虽然模型、选项、设置和配置的组合有时会非常伤脑筋,但大多数情况下实际上只有一些选项和设置的组合是有用的。我设计的这四种事务策略将在本系列的后续文章中详细讨论,并且应该能涵盖您可能会在 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 = ds.getConnection();
dbConnection.setAutoCommit(true);
Statement sql = dbConnection.createStatement();
String stmt = "insert into TRADE ...";
sql.executeUpdate(stmt1);
} finally {
if (dbConnection != null)
dbConnection.close();
}
}
}
注意,在清单 1 中,autoCommit 值设置为 true,这将指示 DBMS 应该在各数据库语句之后提交本地事务。如果在逻辑工作单元(LUW)中维护一个数据库活动,那么这一技巧将非常有用。但是,假设清单 1 中的 processTrade() 方法还将更新 ACCT 表中的余额以反映交易订单的值。在本例中,两个数据库操作是相互独立的,针对 TRADE 表的插入操作将在更新 ACCT 表之后提交给数据库。若 ACCT 表更新失败,没有任何机制可以回滚到对 TRADE 表的更新操作,从而造成数据库中的数据不一致。
此场景又引出了第二个技巧:以编程的方式管理连接。在此技巧中,您将 Connection 对象上的 autoCommit 属性设置为 false,并手动提交或回滚连接。清单 2 演示了此技巧:
清单 2. 包括多个更新的本地事务
public class TradingServiceImpl {
public void processTrade(TradeData trade) throws Exception {
Connection dbConnection = null;
try {
DataSource ds = (DataSource)
(new InitialContext()).lookup("jdbc/MasterDS");
dbConnection = ds.getConnection();
dbConnection.setAutoCommit(false);
Statement sql = dbConnection.createStatement();
String stmt1 = "insert into TRADE ...";
sql.executeUpdate(stmt1);
String stmt2 = "update ACCT set balance...";
sql.executeUpdate(stmt2);
dbConnection.commit();
} catch (Exception up) {
dbConnection.rollback();
throw up;
} finally {
if (dbConnection != null)
dbConnection.close();
}
}
}
注意,在清单 2 中,autoCommit 属性设置为 false,这将通知底层 DBMS 在代码而非数据库中管理连接。在本例中,如果一切正常,您必须调用 Connection 对象上的 commit() 方法;否则,如果出现异常,则调用 rollback() 方法。通过这种方式,您可以在相同的工作单元中协调两个数据库活动。
虽然 Local Transaction 模型现在看来有些过时,但它是本文结束部分介绍的一个主要事务策略的重要元素。
Programmatic Transaction 模型
Programmatic Transaction 模型的名称来自这样一个事实:开发人负责管理事务。在 Programmatic Transaction 模型中,与 Local Transaction 模型不同,您将管理事务,并且将与底层数据库连接 相分离。
与 清单 2 中的示例相似,借助此模型,开发人员将负责从事务管理程序获取一个事务,启动该事务,提交事务,以及(如果出现异常)回滚到事务。您可能已经猜到,这会产生大量易于出错的代码,从而对应用程序中的业务逻辑造成影响。但是,一些事务策略需要使用 Programmatic Transaction 模型。
虽然概念是相同的是,但 Programmatic Transaction 模型的实现在 Spring Framework 和 EJB 3.0 规范中是不同的。我将先使用 EJB 3.0 来演示这个模型的实现,然后使用 Spring Framework 来展示相同的数据库更新。
使用 EJB 3.0 实现编程事务
在 EJB 3.0 中,您将从事务管理程序(换句话说,容器)获取一个事务,方法是对 javax.transaction.UserTransaction 执行 Java Naming and Directory Interface (JNDI) 查找。获取 UserTransaction 之后,您可以调用 begin() 方法来启动事务,调用 commit() 方法来提交事务,并且调用 rollback() 方法以便在出现错误时回滚事务。在此模型中,容器不会自动提交或回滚事务;开发人员需要自己在执行数据库更新的方法编写此行为。清单 3 通过 JPA 展示了使用 EJB 3.0 的 Programmatic Transaction 模型:
清单 3. 使用 EJB 3.0 实现的编程事务
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class TradingServiceImpl implements TradingService {
@PersistenceContext(unitName="trading") EntityManager em;
public void processTrade(TradeData trade) throws Exception {
InitialContext ctx = new InitialContext();
UserTransaction txn = (UserTransaction)ctx.lookup("UserTransaction");
try {
txn.begin();
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
txn.commit();
} catch (Exception up) {
txn.rollback();
throw up;
}
}
}
在带无状态会话 bean 的 Java EE 容器环境中使用 Programmatic Transaction 模型时,您必须通知容器您正在使用编程事务。为此,您需要使用 @TransactionManagement 注释并将事务类型设置为 BEAN。如果您未使用此注释,则容器将假定您使用声明式事务管理(CONTAINER),它是 EJB 3.0 的默认事务类型。在无状态会话 bean 上下文外部的客户机层中使用编程事务时,您不需要设置事务类型。
使用 Spring 实现编程事务
Spring Framework 提供了两种实现 Programmatic Transaction 模型的方法。一种是通过 Spring TransactionTemplate 来实现,另一种是直接使用 Spring 平台事务管理程序。由于我并不热衷于编写匿名内部类和难以理解的代码,因此我将使用第二种技巧来演示 Spring 中的 Programmatic Transaction 模型。
Spring 至少有九种平台事务管理程序。最常用的包括 DataSourceTransactionManager、HibernateTransactionManager、JpaTransactionManager 和 JtaTransactionManager。我的代码示例使用的是 JPA,因此我将展示 JpaTransactionManager 的配置。
要在 Spring 中配置 JpaTransactionManager,只需要使用 org.springframework.orm.jpa.JpaTransactionManager 类在应用程序上下文 XML 文件中定义 bean,并添加一个到 JPA Entity Manager Factory bean 的引用。然后,假定包含应用程序逻辑的类是由 Spring 管理的,将事务管理程序注入到 bean 中,如清单 4 所示:
清单 4. 定义 Spring JPA 事务管理程序
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="tradingService" class="com.trading.service.TradingServiceImpl">
<property name="txnManager" ref="transactionManager"/>
</bean>
如果 Spring 未管理应用程序类,那么您可以在您的方法中引用事务管理程序,方法是在 Spring 上下文中使用 getBean() 方法。
在源代码中,您现在可以使用平台管理程序获取一个事务。执行了所有更新之后,您可以调用 commit() 方法来提交事务,或者调用 rollback() 方法来回滚事务。清单 5 展示了此技巧:
清单 5. 使用 Spring JPA 事务管理程序
public class TradingServiceImpl {
@PersistenceContext(unitName="trading") EntityManager em;
JpaTransactionManager txnManager = null;
public void setTxnManager(JpaTransactionManager mgr) {
txnManager = mgr;
}
public void processTrade(TradeData trade) throws Exception {
TransactionStatus status =
txnManager.getTransaction(new DefaultTransactionDefinition());
try {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
txnManager.commit(status);
} catch (Exception up) {
txnManager.rollback(status);
throw up;
}
}
}
注意清单 5 中 Spring Framework 与 EJB 3.0 之间的差异。在 Spring 中,获取事务(随后启动它)的方法是在平台事务管理程序上调用 getTransaction()。匿名 DefaultTransactionDefinition 类包含关于事务及其行为的详细信息,包括事务名称、隔离级别、传播模式(事务属性)和事务超时(如果存在)。在本例中,我可以仅使用默认值,其名称是空字符串,底层 DBMS 的默认的隔离级别通常为 READ_COMMITTED,事务属性是 PROPAGATION_REQUIRED,以及 DBMS 的默认超时。还需注意,commit() 和 rollback() 方法是使用平台事务管理程序调用的,而不是事务(与 DJB 的情况相同)。
Declarative Transaction 模型
Declarative Transaction 模型,又称作 Container Managed Transactions (CMT),是 Java 平台中最常用的事务模型。在该模型中,容器环境负责启动、提交和回滚事务。开发人员仅负责指定事务的行为。本系列的 第一篇文章 所讨论的大多数事务陷阱都与 Declarative Transaction 模型相关。
Spring Framework 和 EJB 3.0 都利用注释来指定事务行为。Spring 使用 @Transactional 注释,而 EJB 3.0 使用 @TransactionAttribute 注释。在使用 Declarative Transaction 模型时,容器将不会针对检测到的异常自动回滚事务。开发人员必须指定出现异常时在何处以及何时回滚事务。在 Spring Framework 中,您通过使用 @Transactional 注释上的 rollbackFor 属性来指定它。在 EJB 中,您通过调用 SessionContext 上的 setRollbackOnly() 方法来指定它。
清单 6 展示了 Declarative Transaction 模型的 EJB 应用:
清单 6. 使用 EJB 3.0 的声明式事务
@Stateless
public class TradingServiceImpl implements TradingService {
@PersistenceContext(unitName="trading") EntityManager em;
@Resource SessionContext ctx;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void processTrade(TradeData trade) throws Exception {
try {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
} catch (Exception up) {
ctx.setRollbackOnly();
throw up;
}
}
}
清单 7 演示了 Declarative Transaction 模型的 Spring Framework 应用:
清单 7. 使用 Spring 的声明式事务
public class TradingServiceImpl {
@PersistenceContext(unitName="trading") EntityManager em;
@Transactional(propagation=Propagation.REQUIRED,
rollbackFor=Exception.class)
public void processTrade(TradeData trade) throws Exception {
em.persist(trade);
AcctData acct = em.find(AcctData.class, trade.getAcctId());
double tradeValue = trade.getPrice() * trade.getShares();
double currentBalance = acct.getBalance();
if (trade.getAction().equals("BUY")) {
acct.setBalance(currentBalance - tradeValue);
} else {
acct.setBalance(currentBalance + tradeValue);
}
}
}
事务属性
除了回滚指令之外,您还必须指定事务属性,这将定义事务的行为。Java 平台支持六种事务属性,而与您使用的是 EJB 还是 Spring Framework 无关:
* Required
* Mandatory
* RequiresNew
* Supports
* NotSupported
* Never
在描述这些事务属性时,我将使用一个假想的 methodA() 方法,事务属性将应用于这个方法。
如果为 methodA() 指定了 Required 事务属性,并且在已有事务作用域内调用了 methodA(),那么将使用已有的事务作用域。否则,methodA() 将启动一个新的事务。如果事务是由 methodA() 启动的,则它也必须由 methodA() 来终止(提交或回滚)。这是最常用的事务属性,并且是 EJB 3.0 和 Spring 的默认属性。遗憾的是,它的使用并不正确,从而造成了数据完整性和一致性问题。对于本系列后续文章将要讨论的各事务策略,我将更加详细地阐述这个事务属性。
如果为 methodA() 指定了 Mandatory 事务属性,并且在已有事务作用域内调用了 methodA(),那么将使用已有的事务作用域。但是,如果调用 methodA() 时没有事务上下文,则会抛出一个 TransactionRequiredException,指示必须在调用 methodA() 之前呈现事务。这个事务属性应用于本文下一部分将要讨论的 Client Orchestration 事务策略。
RequiresNew 事务属性非常有趣。许多时候,我会发现这个属性被误用或误解。methodA() 指定了 RequiresNew 属性,并且在有或没有事务上下文的情况下调用了 methodA(),那么新事务将始终由 methodA() 启动(和终止)。这意味着,如果在另一个事务(比如说 Transaction1)的上下文中调用了 methodA(),那么 Transaction1 将暂停,同时会启动一个新的事务(Transaction2)。当 methodA() 结束时,Transaction2 将提交或回滚,并且 Transaction1 将恢复。这显然违背了事务的 ACID(atomicity、consistency、isolation 和 durability)属性(特别是 atomicity 属性)。换句话说,所有数据库更新都不再包含在一个单一的工作单元中。如果 Transaction1 将进行回滚,则由 Transaction2 提交的更改将仍然被提交。如果是这种情况,那么事务属性有什么好处呢?如本系列第一篇文章所述,这个事务属性仅用于独立于底层事务的数据库操作(比如审计或记录,在本例中为 Transaction1)。
Supports 事务属性也是我发现大多数开发人员未完全理解或掌握的一个地方。如果为 methodA() 指定了 Supports 事务属性,并且在已有事务的作用域中调用了 methodA(),则 methodA() 将在该事务的作用域中执行。但是,如果在没有事务上下文的情况下调用了 methodA(),则不会启动任何事务。此属性主要用于针对数据库的只读操作。如果是这种情况,为何不指定 NotSupported 事务属性(在下一段中讨论)呢?毕竟,该属性将确保方法在没有事务的情况下运行。答案非常简单。在已有事务的上下文中调用查询操作会导致从数据库事务日志中读取数据(换句话说,已更新的数据),而不在事务作用域中运行会导致查询从表中读取未修改的数据。举例来说,如果您插入一个新的交易订单到 TRADE 表中,然后(在相同的事务中)获取所有交易订单的列表,则未提交的交易将出现在列表中。但是,如果您使用的是 NotSupported 事务属性,那么它会造成数据库查询从表中而不是从事务日志中读取数据。因此,在上一个示例中,您将不会看到未提交的交易。这并不一定是一件坏事;这将由您的用例和业务逻辑决定。
NotSupported 事务属性指定被调用的方法将不使用或启动事务,无论是否呈现了事务。如果为 methodA() 指定了 NotSupported 事务属性,并且在某个事务的上下文中调用了 methodA(),则该事务将暂停直到 methodA() 结束。当 methodA() 结束时,原始事务将被恢复。这个事务属性只有少许用例,并且它们主要涉及数据库存储过程。如果您尝试在已有事务上下文的作用域中调用数据库存储过程,并且数据库存储过程包含一个 BEGIN TRANS,或者对于 Sybase 的情况,在未连接模式中运行,则会抛出一个异常,指示已经存在一个事务无法启动新事务。(换句话说,内嵌事务不受支持)。几乎所有的容器都使用 Java Transaction Service (JTS) 作为默认的 JTA 事务实现。不支持内嵌事务的是 JTS 而不是 Java 平台。如果您无法修改数据库存储过程,那么您可以使用 NotSupported 属性来暂停已有事务上下文,以避免这种致命的异常。但是,其影响是您不能在相同的 LUW 中对数据库执行原子更新。这是一种权衡,但有时可以让您迅速脱离困境。
Never 或许是最有趣的事务属性。它的行为类似于 NotSupported 事务属性,但存在一个重要差异:如果使用 Never 事务属性调用方法时已经存在某个事务上下文,则会抛出一个异常,指示您在调用该方法时不允许使用这个事务。我能想到的针对此事务属性的唯一一个用例就是用于测试。它提供了一种简单的方法,用于验证当您调用特定的方法时某个事务是否存在。如果您在调用相应的方法时使用了 Never 事务属性并且接收到了一个异常,则知道事务已经呈现。如果允许执行方法,则您知道事务未被呈现。这是确保事务策略坚固的理想方法。
事务策略
本文描述的事务模型形成了即将介绍的事务策略的基础。在开始构建事务策略之前,完全理解这些模型之间的差异以及它们的运行原理是非常重要的。可以在大多数业务应用程序场景中使用的主要事务策略包括:
* Client Orchestration 事务策略
* API Layer 事务策略
* High Concurrency 事务策略
* High-Speed Processing 事务策略
我将在此处简要介绍这些策略,并将在本系列的后续文章中详细讨论它们。
当来自客户机层的基于多服务器或基于模型的调用完成单一工作单元时,将使用 Client Orchestration 事务策略。此处的客户机层可以表示来自 Web 框架、门户应用程序、桌面系统或工作流产品或业务流程管理(BPM)组件的调用。从本质上说,客户机层拥有处理流以及完成特定请求所需的 “步骤”。举例来说,要添加一个交易订单,假定您需要将交易插入到数据库中,然后更新客户的帐户余额以反映交易的值。如果应用程序的 API 层非常细粒度化,那么您需要调用客户机层中的两个方法。在此场景中,事务工作单元必须位于客户机层中以确保自动化的工作单元。
当粗粒度方法充当后端功能的主要入口点时,将使用 API Layer 事务策略。(如果愿意,可以将它们称作 services)。在此场景中,客户机(基于 Web、基于 Web 服务、基于消息或者甚至桌面)向后端发起单个调用以执行特定的请求。使用上文提到的交易订单场景,在本例中您将拥有一个入口点方法(比如说 processTrade())由客户机层调用。然后,这个方法将包含插入交易订单和更新帐户所需的业务流程。我将这个策略指定为这个名称的原因是,在大多数情况下,后端处理功能会通过使用接口或 API 向客户应用程序公开。这是最常用的事务策略之一。
High Concurrency 事务策略是 API Layer 事务策略的一个变体,它用于不支持通过 API 层长时间运行事务的应用程序(通常出于性能或可伸缩性需求的原因)。顾名思义,此策略主要在从用户的角度支持高度并发性的应用程序中使用。事务在 Java 平台的开销非常大。根据您所使用的数据库,它们可以造成在数据库中出现锁定,独占资源,在吞吐量方面拖慢应用程序,并且在某些情况下甚至造成数据库死锁。这种事务策略内部的主要思想是缩短事务作用域,以便您能够最大限度地减少数据库中的死锁,同时仍然为任何特定的客户机请求维持自动工作单元。在某些情况下,您可能需要重构应用程序逻辑,以支持这种事务策略。
High-Speed Processing 事务策略或许是事务策略的最极端。如果您需要从应用程序中获取最快的处理时间(以及吞吐量),并且仍然在处理中维持一定程序的事务原子性,那么可以使用它。虽然这种策略从数据完整性和一致的角度来说引入了一些风险,但如果正确实现,它将成为 Java 平台中速度可能是最快的事务策略。它可能是这四个事务策略中最难以实现的一个。
结束语
从这篇概述中可以看到,开发一个有效的事务策略并非总是一项简单的任务。在解决数据完整性和一致问题时需要考虑各种事项、选项、模型、框架、配置和技巧。在使用应用程序和事务的多年经验中,我发现虽然模型、选项、设置和配置的组合有时会非常伤脑筋,但大多数情况下实际上只有一些选项和设置的组合是有用的。我设计的这四种事务策略将在本系列的后续文章中详细讨论,并且应该能涵盖您可能会在 Java 平台业务应用程序开发中遇到的大多数场景。需要注意:这些策略并不是简单的 “一劳永逸” 解决方案。在某些情况下,一些实现还需要重新构建源代码或者重新设计应用程序。对于这种情况,您只需要问自己一个问题:“我的数据的完整性和一致性有多重要?”在大多数情况下,与损坏数据招致的风险和成本相比,重构工作并不算什么。
发表评论
-
JAVA生成二维码详解
2013-02-22 23:09 1882最近有一新项目,用到了二维码,特写下来与大家分享。 imp ... -
weblogic10 创建数据源的驱动与连接池问题
2010-10-16 09:51 3235在创建数据源时无法找到驱动或无法加载驱动的问题: 在创建数据源 ... -
weblogic10 端口被占用的解决方法
2010-10-16 09:46 2181找到您创建的用户域下面的config文件夹下的config.x ... -
BPEL的基本思想
2010-03-11 15:03 1769许多开发人员觉得BPEL很神秘,不知道到底是什么意思。主要是因 ... -
使用Java生成pdf
2010-03-04 11:12 1788iText是一个能够快速产 ... -
Java中关于文件的绝对路径与相对路径的总结
2010-01-05 16:05 21971.基本概念的理解 ... -
Java对象池技术的原理及其实现
2010-01-05 15:14 937Java对象的生命周期分析 Java对象的生命周期大致包 ... -
详解JAVA POI导出EXCEL报表的操作(包括各种格式及样式的实现)
2009-11-08 12:35 23012这两天在做项目时,最后一道工序为将查询的报表导出为EXCEL, ... -
Hibernate主键生成 Key Generator 详解
2009-09-29 17:35 1703Hibernate 主键生成器是负责生成数据表记录的主键,通常 ... -
利用Servlet中Listener解决用户的动态上线离线问题
2009-09-24 14:56 1981首先我们来看一下我自己项目中的一个Listener的实际应用( ... -
各类Http请求状态(status)及其含义
2009-09-24 14:43 1234AJAX中请求远端文件、或在检测远端文件是否掉链时,都需要了解 ... -
JSP分页代码(最原始的分页思想)
2009-09-24 14:39 3256<%@ page language="java ... -
JAVA 将数字字符串转换成中文形式
2009-09-24 14:34 1513public class MainClass3 { ... -
生成可执行jar文件的方法
2009-09-24 14:33 1129若要生成一个名为 cal.jar 的可执行jar文件:(文件名 ... -
JAAS:灵活的Java安全机制
2009-09-15 14:49 2481Java Authentication Authorizati ... -
Maven入门--概念与实例
2009-09-15 14:46 11561 关键名词 Project:任何您想build的事 ... -
从追MM谈Java的23种设计模式
2009-09-02 10:22 1049设计模式做为程序员的 ... -
JSP编程进度条设计实例
2009-08-25 10:44 1129本文介绍的技术是把繁重的计算任务分离开来,由一个独立的线程运行 ... -
熟练的Java程序员应该掌握的技术
2009-08-25 10:22 13681、语法:Java程序员必须比较熟悉语法,在写代码的时候IDE ... -
Eclipse+Tomcat远程调试配置
2009-08-25 10:10 1590在做远程调试时,在windows系统和非windows系统下的 ...
相关推荐
本文将深入探讨Java中的事务设计策略,包括本地事务模型、编程式事务模型、声明式事务模型以及几种事务设计模式。 首先,我们来理解事务的基本概念。事务是数据库操作的基本单元,它保证了一组操作要么全部成功,...
综上所述,Java事务设计策略涉及多种不同的事务模型和技术,每种模型和技术都有其适用场景和优势。理解这些基本概念和最佳实践对于构建健壮、可靠的企业级Java应用程序至关重要。开发者可以根据具体的应用需求和环境...
Java事务设计模式是复杂且至关重要的,开发者需要理解不同事务模型的适用场景,熟悉JTA提供的工具和接口,以及如何避免编程陷阱。正确地设计和实现事务处理,不仅可以确保数据的完整性和一致性,还能提高系统的可...
### Java与数据库事务详解 ...最后,文章讨论了EJB事务模型中的两种事务管理方式以及乐观锁与悲观锁的区别。通过对这些知识点的学习,开发者可以更好地理解和掌握如何在Java应用程序中有效地管理和控制数据库事务。
#### 三、Java事务的实现原理 Java事务的实现主要依赖于底层数据库的支持。不同的数据库管理系统(DBMS)对事务的支持程度不同,但大多数现代关系型数据库都支持ACID事务。 - **原子性**:由数据库引擎实现,确保...
"JAVA WEB日常事务管理系统"是一个基于Java Web技术构建的应用,旨在帮助用户管理和处理日常工作中的各种事务,如邮件系统、公告发布以及会议管理等。这个系统采用了一些主流的Java开发框架,如Struts和Hibernate,...
6. **开源工具和库**:如Atomikos、Bitronix等事务管理器,以及MyBatis Plus、Hibernate等ORM框架,它们在处理分布式事务时提供了强大的支持。 7. **补偿事务(Compensating Transaction, CTS)**:当事务操作无法...
Java Web项目企业事务管理系统源码,详细的代码注释 本系统的开发工具具体如下。 ● 系统开发平台:MyEclipse 6.5。 ● 数据库管理系统软件:MySQL 5.0。 ● 运行平台:Windows 2000/Windows XP/Windows 2003/...
Java+Web项目企业事务管理系统源码是一套完整的Java Web应用程序,用于实现企业级的事务管理。这个系统的核心目标是提供高效、可靠且易于维护的事务处理能力,以满足企业日常运营中的各种业务需求。在本系统中,Java...
Java中有三种事务模型: 1. 本地事务模型:在本地事务模型中,事务管理由本地资源管理器负责,如数据库驱动和DBMS或JMS提供者。开发人员直接管理数据库连接,而事务的管理则交由资源管理器处理。 2. 编程式事务模型...
4. XA两阶段提交:遵循ACID(原子性、一致性、隔离性和持久性)原则的传统分布式事务模型。Seata也支持这种模式,但在高并发场景下可能存在性能瓶颈。 Seata的设计理念是轻量级和自治,这意味着它尽可能减少对业务...
这是一个基于Java技术的Web项目,主要关注的是企业事务管理系统的实现。这个系统源码的提供,对于学习和理解Java在企业级应用中的实践具有很高的价值。以下将详细讲解与Java Web项目相关的知识点。 1. **Java编程...
### Java微服务系统分布式事务解决方案 #### 一、CAP定理与分布式系统设计原则 **CAP理论**在分布式系统的设计中扮演着至关重要的角色。它指出,在分布式计算环境中,任何共享数据系统都无法同时保证一致性...
Java事务设计策略是Java开发中一个至关重要的主题,它直接影响着应用程序的数据完整性和并发性能。在深入探讨前,我们先明确几个核心概念:事务、ACID特性、JTA(Java Transaction API)、JTS(Java Transaction ...
Java MySQL 三层模型和DAO模式在汽车租赁系统中的应用 汽车租赁系统是一个常见的企业级应用程序,它使用Java作为主要的编程语言,结合MySQL数据库来管理汽车租赁业务的相关数据。在这个系统中,通常会采用经典的三...
在开发过程中,我们还需要遵循良好的编程实践,比如编写清晰的注释、进行单元测试以保证代码质量,以及使用MVC(模型-视图-控制器)设计模式来分离业务逻辑和用户界面。 最后,进行系统集成和测试,确保所有模块...
在 Java 中,存在两种线程模型:主线程和子线程。主线程是程序的入口点,而子线程是由主线程创建的辅助线程。子线程的运行结果可以通过阻塞的方式来获取。在 Java 中,我们可以使用 Callable 或 Runnable 接口来实现...
然而,对于多个数据源,我们需要更复杂的策略,比如使用JtaTransactionManager,它支持JTA(Java Transaction API),可以跨多个数据源进行事务管理。 接下来,我们讨论如何利用注解来实现多数据源事务。Spring的@...
12. **最佳实践**:在实际应用中,应根据业务场景选择合适的事务模型,同时考虑性能、可用性和可扩展性。对于低延迟和高并发的场景,可能需要牺牲部分一致性以换取更高的系统效率。 以上就是Java分布式服务开发中...