2023-07-19 10:23:49 +08:00

127 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 事务管理
MyBatis-Flex 提供了一个名为 `Db.tx()` 的方法<Badge type="tip" text="^1.0.6" />,用于进行事务管理,若使用 Spring 框架的场景下,也可使用 `@Transactional` 注解进行事务管理。
`Db.tx()` 方法定义如下:
```java
boolean tx(Supplier<Boolean> supplier);
boolean tx(Supplier<Boolean> supplier, Propagation propagation);
<T> T txWithResult(Supplier<T> supplier);
<T> T txWithResult(Supplier<T> supplier, Propagation propagation);
```
方法:
- tx返回结果为 Boolean返回 `null` 或者 `false` 或者 抛出异常,事务回滚
- txWithResult返回结果由 `Supplier` 参数决定,只有抛出异常时,事务回滚
参数:
- **supplier**:要执行的内容(代码)
- **propagation**:事务传播属性
事务传播属性 `propagation` 是一个枚举类,其枚举内容如下:
```java
//若存在当前事务,则加入当前事务,若不存在当前事务,则创建新的事务
REQUIRED(0),
//若存在当前事务,则加入当前事务,若不存在当前事务,则已非事务的方式运行
SUPPORTS(1),
//若存在当前事务,则加入当前事务,若不存在当前事务,则抛出异常
MANDATORY(2),
//始终以新事务的方式运行,若存在当前事务,则暂停(挂起)当前事务。
REQUIRES_NEW(3),
//以非事务的方式运行,若存在当前事务,则暂停(挂起)当前事务。
NOT_SUPPORTED(4),
//以非事务的方式运行,若存在当前事务,则抛出异常。
NEVER(5),
//暂时不支持
NESTED(6),
```
`Db.tx()` 代码示例:
```java
Db.tx(() -> {
//进行事务操作
return true;
});
```
`tx()` 方法抛出异常,或者返回 false或者返回 null则回滚事务。只有正常返回 true 的时候,进行事务提交。
## 嵌套事务
示例代码:
```java
Db.tx(() -> {
//进行事务操作
boolean success = Db.tx(() -> {
//另一个事务的操作
return true;
});
return true;
});
```
支持无限极嵌套,默认情况下,嵌套事务直接的关系是:`REQUIRED`(若存在当前事务,则加入当前事务,若不存在当前事务,则创建新的事务)。
## @Transactional
MyBatis-Flex 已支持 Spring 框架的 `@Transactional`,在使用 SpringBoot 的情况下,可以直接使用 `@Transactional` 进行事务管理。
同理,使用 Spring 的 `TransactionTemplate` 进行事务管理也是没问题的。
> 注意:若项目未使用 SpringBoot只用到了 Spring需要参考 MyBatis-Flex 的 [FlexTransactionAutoConfiguration](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/FlexTransactionAutoConfiguration.java)
> 进行事务配置,才能正常使用 `@Transactional` 注解。
## 特征
- 1、支持嵌套事务
- 2、支持多数据源
> 注意在多数据源的情况下所有数据源的数据库请求Connection会执行相同的 commit 或者 rollback但并非原子操作。例如
```java
@Transactional
public void doSomething(){
try{
DataSourceKey.use("ds1");
Db.updateBySql("update ....");
}finally{
DataSourceKey.clear()
}
try{
DataSourceKey.use("ds2");
Db.updateBySql("update ...");
}finally{
DataSourceKey.clear()
}
//抛出异常
int x = 1/0;
}
```
在以上的例子中,两次 `Db.update(...)` 虽然是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候,
它们都会进行回滚rollback
以上提到的 `并非原子操作`,指的是:
>假设在回滚的时候,恰好其中一个数据库出现了异常(比如 网络问题数据库崩溃此时可能只有一个数据库的数据正常回滚rollback
> 但无论如何MyBatis-Flex 都会保证在同一个 `@Transactional` 中的多个数据源,保持相同的 commit 或者 rollback 行为。