Skip to content

Commit

Permalink
Update 13.批量操作.md
Browse files Browse the repository at this point in the history
  • Loading branch information
nieqiurong committed Oct 26, 2023
1 parent 0c9dc78 commit c365c16
Showing 1 changed file with 86 additions and 37 deletions.
123 changes: 86 additions & 37 deletions docs/01.指南/03.扩展/13.批量操作.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,60 @@ article: false

- 事务需要手动自行控制(默认false)

注意: autoCommit参数在Spring项目下是无效的,具体见SpringManagedTransactionFactory#newTransaction,在原生mybatis下可用
::: warning

- 执行返回值为批量处理结果,业务可根据返回值判断是否成功
autoCommit参数在Spring项目下是无效的,具体见SpringManagedTransactionFactory#newTransaction,在原生mybatis下可用

- saveOrUpdate是个比较有争议的方法,建议批量操作保持为简单的新增或更新操作
:::

注意: 如果使用批量的sqlSession去执行查询业务的话,就会变得每次都需要flushStatements
- 执行返回值为批量处理结果,业务可根据返回值判断是否成功

- 数据能否写入或更新取决于代码能否正确执行到flushStatements

- 支持Spring与非Spring项目使用

- 执行抛出异常为PersistenceException

# 说明:
- saveOrUpdate是个比较有争议的方法,个人建议批量操作保持为简单的新增或更新操作


## 执行类

## MybatisBatch<?>
### MybatisBatch<?>

- 泛型为具体 **实际数据类型**
- sqlSessionFactory可通过容器获取,非Spring容器下可在自行初始化Mybatis时将上下文记录起来
- dataList为实际的批量数据处理 (非空)

## MybatisBatch.Method<?>
### MybatisBatch.Method<?>

- 泛型为 **具体实体**
- mapperClass为具体的实际Mapper类

## 使用方式
## 使用说明

1. 构建MybatisBatch (将数据与sqlSessionFactory绑定起来)
2. 构建MybatisBatch.Method (确定执行执行Mapper类方法)
3. 执行操作 (执行处理操作,将批量参数转换为实际mapper需要的参数)

示例一: 批量插入用户(数据类型为实体)
## 使用示例

框架提供了一个MybatisBatchUtils进行静态方法调用.

### execute

适用于insert,update,delete操作

#### 示例一: 数据类型为实体

```java
List<H2User> userList = List.of(new H2User(2000L, "测试"), new H2User(2001L, "测试"));
List<H2User> userList = Arrays.asList(new H2User(2000L, "测试"), new H2User(2001L, "测试"));
MybatisBatch<H2User> mybatisBatch = new MybatisBatch<>(sqlSessionFactory, userList);
MybatisBatch.Method<H2User> method = new MybatisBatch.Method<>(H2UserMapper.class);
mybatisBatch.execute(method.insert());

// 简写
MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
MybatisBatchUtils.execute(sqlSessionFactory, h2UserList, mapperMethod.insert());
```

示例二: 批量插入用户(数据类型为非实体)
#### 示例二: 数据类型为非实体

```java
List<Long> ids = Arrays.asList(120000L, 120001L);
Expand All @@ -68,18 +75,9 @@ mybatisBatch.execute(method.insert(id -> {
h2User.setTestId(id);
return h2User;
}));

// 简写
MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
MybatisBatchUtils.execute(sqlSessionFactory, ids, mapperMethod.insert(id -> {
// 将id转换为实体
H2User h2User = new H2User();
h2User.setTestId(id);
return h2User;
}));
```

示例三: 自定义方法插入一
#### 示例三: 自定义方法插入(无注解)

```java
// mapper方法(方法参数无注解)
Expand All @@ -97,13 +95,9 @@ for (int i = 0; i < 1000; i++) {
MybatisBatch<H2User> mybatisBatch = new MybatisBatch<>(sqlSessionFactory, h2UserList);
MybatisBatch.Method<H2User> method = new MybatisBatch.Method<>(H2UserMapper.class);
mybatisBatch.execute(method.get("myInsertWithoutParam"));

//简写
MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
MybatisBatchUtils.execute(sqlSessionFactory, h2UserList, mapperMethod.get("myInsertWithoutParam"));
```

示例四: 自定义方法插入(注解)
#### 示例四: 自定义方法插入(注解)

```java
// 方法参数带注解
Expand All @@ -126,18 +120,73 @@ mybatisBatch.execute(method.get("myInsertWithParam", (user) -> {
map.put("user1", user);
return map;
}));
```

### saveOrUpdate

执行保存或更新

::: warning

重点注意跨sqlSession下缓存和数据感知问题

:::

`saveOrUpdate(BatchMethod<T> insertMethod, BiPredicate<BatchSqlSession, T> insertPredicate, BatchMethod<T> updateMethod)`

- insertMethod: 指定insert操作处理

- insertPredicate: 指定insert操作处理条件

::: warning

// 简写
注意这里的BatchSqlSession,使用这个进行查询操作会每次都执行一次flushStatements.

如果在一次处理中,如果有两条记录相同的数据,在跨sqlSession中会执行两次插入导致主键冲突,而共享sqlsesion下会执行一次插入和一次更新

:::

- updateMethod: 指定update操作处理




#### 跨sqlSession

```java
@Autowired
private H2UserMapper userMapper;

List<H2User> h2UserList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
h2UserList.add(new H2User(Long.valueOf(40000 + i), "test" + i));
}
MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);
MybatisBatchUtils.execute(sqlSessionFactory, h2UserList, mapperMethod.get("myInsertWithParam", (user) -> {
Map<String, Object> map = new HashMap<>();
map.put("user1", user);
return map;
}));

new MybatisBatch<>(sqlSessionFactory,h2UserList).saveOrUpdate(
mapperMethod.insert(), // 指定insert方法
((sqlSession, h2User) -> userMapper.selectById(h2User.getTestId()) == null), //判断条件,引用另个mapper方法
mapperMethod.updateById()); // 指定update方法
```

#### 共用sqlSession

```java
List<H2User> h2UserList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
h2UserList.add(new H2User(Long.valueOf(50000 + i), "test" + i));
}
MybatisBatch.Method<H2User> mapperMethod = new MybatisBatch.Method<>(H2UserMapper.class);

//方式一
new MybatisBatch<>(sqlSessionFactory,h2UserList).saveOrUpdate( mapperMethod.insert(), // 指定insert方法
((sqlSession, h2User) -> sqlSession.selectList(H2UserMapper.class.getName() + ".selectById", h2User.getTestId()).isEmpty()), //判断条件,共用sqlSession
mapperMethod.updateById()); // 指定update方法
```

## 事务处理示例
### 事务处理

#### Spring事务处理示例一

```java
@Autowired
Expand Down

0 comments on commit c365c16

Please sign in to comment.