并发事务处理:策略、实现与应用
发布时间: 2025-08-17 02:17:23 阅读量: 1 订阅数: 3 

### 并发事务处理:策略、实现与应用
在并发控制的领域中,事务处理是一个核心的概念。不同的事务处理策略和实现方式,对于系统的性能、可靠性和可维护性有着重要的影响。本文将深入探讨并发事务处理的相关知识,包括乐观和保守事务策略、事务参与者的接口与实现、事务的创建过程以及可否决变更的处理方式。
#### 1. 乐观与保守事务策略
在并发控制中,有两种互补的事务策略:乐观事务和保守事务。
- **乐观事务**:参与者可以随时加入事务,但不一定能提交事务。当竞争的可能性较低,且回滚成本可以接受时,乐观策略是最佳选择。
- **保守事务**:参与者不一定能加入事务,但一旦加入,就可以保证提交事务。当事务中执行的操作难以或无法撤销时,保守策略更为合适。
然而,在实际应用中,纯粹的乐观或保守事务策略很少见,并且很容易创建允许混合策略的框架。
#### 2. 事务参与者
事务参与者是事务处理中的关键元素。在结构化事务框架中,每个类除了支持加入、提交、中止和创建事务的方法外,还必须在其公共方法中添加事务控制参数。
方法的形式如下:
```java
ReturnType aMethod(Transaction t, ArgType args) throws...
```
例如,`BankAccount.deposit` 方法的声明如下:
```java
void deposit(Transaction t, long amount) throws ...
```
事务信息必须在事务执行过程中调用的所有方法中传播,包括对辅助对象的嵌套调用。最简单的事务参数是一个唯一标识每个事务的事务键。
此外,一些事务框架可能会采用一些技巧来隐藏事务控制的细节,例如将事务标识符隐藏为线程特定的数据、限制控制范围、通过反射或扫描字节码确定参与者,以及通过序列化组件状态或获取锁来实现半自动化回滚。但这些技巧会带来额外的开销和使用限制,在轻量级事务框架中可能并不值得。
#### 3. 事务参与者的接口
参与者类必须实现定义事务控制方法的接口。以下是一个简单但具有代表性的接口:
```java
class Failure extends Exception {}
interface Transactor {
// 进入新事务,如果可能则返回 true
public boolean join(Transaction t);
// 如果此事务可以提交,则返回 true
public boolean canCommit(Transaction t);
// 更新状态以反映当前事务
public void commit(Transaction t) throws Failure;
// 回滚状态(无异常;如果不适用则忽略)
public void abort(Transaction t);
}
```
此外,还需要一个接口或类来描述 `Transaction` 对象本身。在讨论基本操作时,可以使用一个无操作版本:
```java
class Transaction {
// 可以在这里添加任何内容
}
```
#### 4. 事务参与者的实现
事务参与者必须同时支持事务参与者接口和描述其基本操作的接口。例如:
```java
interface TransBankAccount extends Transactor {
public long balance(Transaction t) throws Failure;
public void deposit(Transaction t, long amount) throws InsufficientFunds, Failure;
public void withdraw(Transaction t, long amount) throws InsufficientFunds, Failure;
}
```
实现事务类的最常见方法是将底层状态表示拆分为单独的辅助类,使用临时操作或检查点方法。这种方法在支持持久化的事务框架中尤为合适。
事务方法的实现可以从乐观到保守策略不等。以下表格总结了使用 `Transaction` 参数 `tx` 调用的方法的端点亮点:
| 方法 | 乐观策略 | 保守策略 |
| --- | --- | --- |
| join | - 创建状态副本并将其与 `tx` 关联(例如在哈希表中),同时记录状态的版本信息<br>- 返回 `true` | - 如果已经参与冲突事务,则返回 `false`,可选地先尝试等待事务完成<br>- 询问操作方法中引用的所有其他对象是否可以加入;如果有任何对象不能加入,则返回 `false`<br>- 备份当前状态,以便在中止时恢复<br>- 记录 `tx` 为当前事务;返回 `true` |
| 操作方法 | - 如果 `tx` 不是已知事务,则先加入 `tx`,如果加入失败则失败<br>- 在当前状态上执行基本操作,并/或通过调用其他对象的方法并传递参数 `tx`,记录所有此类对象的标识<br>- 任何失败时,将 `tx` 标记为不可提交 | - 如果 `tx` 不是当前事务,则失败<br>- 在当前状态上执行基本操作,并/或通过调用其他已加入对象的方法并传递参数 `tx`<br>- 任何失败时,将当前事务标记为不可提交 |
| abort | - 丢弃与 `tx` 关联的所有簿记信息<br>- 传播到所有其他已知参与者 | - 如果 `tx` 是当前事务,将状态重置为备份副本,并记录没有当前事务<br>- 传播到所有其他已知参与者 |
| commit | - 将与 `tx` 关联的表示保存为当前状态<br>- 传播到所有已知参与者<br>- 丢弃备份;记录没有当前事务 | - 传播到所有已知参与者 |
| canCommit | - 如果自加入 `tx` 以来发生了任何冲突提交,或者任何其他冲突事务已经承诺提交,则返回 `false`<br>- 询问操作过程中引用的所有其他对象是否可以提交;如果有任何对象不能提交,则返回 `false`<br>- 记录 `tx` 已承诺提交;返回 `true` | - 询问其他参与者,如果有任何参与者不能提交,则返回 `false`<br>- 除非在操作过程中发生本地失败,否则返回 `true` |
以下是一个简单的 `SimpleTransBankAccount` 类的实现示例:
```java
class SimpleTransBankAccount implements TransBankAccount {
protected long balance = 0;
protected long workingBalance = 0; // 单个影子副本
protected Transaction currentTx = null; // 单个事务
public synchronized long balance(Transaction t) throws Failure {
if (t != currentTx) throw new Failure();
return workingBalance;
}
public synchronized void deposit(Transaction t, long amount) throws InsufficientFunds, Failure {
if (t != currentTx) throw new Failure();
if (workingBalance < -amount)
throw new InsufficientFunds();
workingBalance += amount;
```
0
0
相关推荐









