增加SpringBatch的支持,Linux下开发,有大小写名称的问题.所以AccountMapper改了下名字. 无法install到本地测试,没写测试

This commit is contained in:
zhj149 2025-04-28 13:47:12 +08:00
parent 82ed8229e2
commit ea03a5f3df
11 changed files with 543 additions and 0 deletions

View File

@ -40,6 +40,16 @@
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>datasource-decorator-spring-boot-autoconfigure</artifactId>

View File

@ -0,0 +1,98 @@
package com.mybatisflex.spring.batch;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryWrapper;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
import java.util.*;
import static org.springframework.util.Assert.notNull;
import static org.springframework.util.ClassUtils.getShortName;
/**
* 游标模式读取
* @author zhangjian
*/
public class MyBatisFlexCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
/**
* 当前的mapper
*/
private BaseMapper<T> mapper;
/**
* 拼接的入参列表
*/
private QueryWrapper queryWrapper;
/**
*
*/
private Cursor<T> cursor;
/**
*
*/
private Iterator<T> cursorIterator;
public MyBatisFlexCursorItemReader() {
setName(getShortName(MyBatisFlexCursorItemReader.class));
}
/**
* 当前的mapper对象
* @param mapper
*/
public void setMapper(BaseMapper<T> mapper) {
this.mapper = mapper;
}
/**
* 当前的参数对象
* @param queryWrapper
*/
public void setQueryWrapper(QueryWrapper queryWrapper) {
this.queryWrapper = queryWrapper;
}
@Override
protected T doRead() throws Exception {
T next = null;
if (cursorIterator.hasNext()) {
next = cursorIterator.next();
}
return next;
}
@Override
protected void doOpen() {
if (Objects.isNull(this.mapper) || Objects.isNull(this.queryWrapper)) {
throw new IllegalArgumentException("mapper or queryWrapper is required.");
}
this.cursor = this.mapper.selectCursorByQuery(queryWrapper);
cursorIterator = cursor.iterator();
}
@Override
protected void doClose() throws Exception {
if (cursor != null) {
cursor.close();
}
cursorIterator = null;
}
/**
* Check mandatory properties.
*
* @see InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
notNull(mapper, "A BaseMapper is required.");
notNull(queryWrapper, "A queryWrapper is required.");
}
}

View File

@ -0,0 +1,76 @@
package com.mybatisflex.spring.batch;
import com.mybatisflex.core.BaseMapper;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.EmptyResultDataAccessException;
import java.util.List;
import java.util.Objects;
import static org.springframework.util.Assert.notNull;
/**
* mybatisflex实现的数据写入工具
* @author zhangjian
* @param <T>
*/
public class MybatisFlexBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(MybatisFlexBatchItemWriter.class);
private BaseMapper<T> mapper;
private boolean assertUpdates = true;
/**
* Public setter for the flag that determines whether an assertion is made that number of BatchResult objects returned
* is one and all items cause at least one row to be updated.
*
* @param assertUpdates the flag to set. Defaults to true;
*/
public void setAssertUpdates(boolean assertUpdates) {
this.assertUpdates = assertUpdates;
}
/**
* mapper对象
* @param mapper
*/
public void setMapper(BaseMapper<T> mapper) {
if (Objects.isNull(mapper))
throw new RuntimeException("MybatisFlex Mapper can't be null!");
this.mapper = mapper;
}
/**
* Check mandatory properties - there must be an SqlSession and a statementId.
*/
@Override
public void afterPropertiesSet() {
notNull(mapper, "A Mapper is required.");
}
/**
* {@inheritDoc}
*/
@Override
public void write(final List<? extends T> items) {
if (!items.isEmpty()) {
LOGGER.debug(() -> "Executing batch with " + items.size() + " items.");
int results = this.mapper.insertBatch((List<T>) items);
if (assertUpdates) {
if (results != items.size()) {
throw new EmptyResultDataAccessException(
"Items.size + " + items.size() + " doesn't match the number of updated rows: " + results, 1);
}
}
}
}
}

View File

@ -0,0 +1,84 @@
package com.mybatisflex.spring.batch;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.mybatis.spring.batch.MyBatisPagingItemReader;
import org.springframework.batch.item.database.AbstractPagingItemReader;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.springframework.util.Assert.notNull;
import static org.springframework.util.ClassUtils.getShortName;
/**
* mybatis-flex的分页读取器
* @author zhangjian
* @param <T> 实体类型
*/
public class MybatisFlexPagingItemReader<T> extends AbstractPagingItemReader<T> {
/**
* 当前的mapper
*/
private BaseMapper<T> mapper;
/**
* 拼接的入参列表
*/
private QueryWrapper queryWrapper;
public MybatisFlexPagingItemReader() {
setName(getShortName(MyBatisPagingItemReader.class));
}
/**
* 当前的mapper对象
* @param mapper
*/
public void setMapper(BaseMapper<T> mapper) {
this.mapper = mapper;
}
/**
* 当前的参数对象
* @param queryWrapper
*/
public void setQueryWrapper(QueryWrapper queryWrapper) {
this.queryWrapper = queryWrapper;
}
/**
* Check mandatory properties.
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
notNull(mapper, "mapper is required.");
notNull(queryWrapper, "querywrapper is required.");
}
@Override
protected void doReadPage() {
if (results == null) {
results = new CopyOnWriteArrayList<>();
} else {
results.clear();
}
Page<T> paginate = mapper.paginate(getPage() + 1, getPageSize(), queryWrapper);
results.addAll(paginate.getRecords());
}
@Override
protected void doJumpToPage(int itemIndex) {
if (results == null) {
results = new CopyOnWriteArrayList<>();
} else {
results.clear();
}
Page<T> paginate = mapper.paginate(itemIndex + 1, getPageSize(), queryWrapper);
results.addAll(paginate.getRecords());
}
}

View File

@ -0,0 +1,55 @@
package com.mybatisflex.spring.batch.builder;
import com.mybatisflex.spring.batch.MybatisFlexBatchItemWriter;
import com.mybatisflex.core.BaseMapper;
import java.util.Optional;
/**
* 构造MybatisFlex数据的写入工具
*
* @author zhangjian
*
* @see MybatisFlexBatchItemWriter
*/
public class MyBatisFlexBatchItemWriterBuilder<T> {
/**
* mapper对象
*/
private BaseMapper<T> mapper;
private Boolean assertUpdates;
/**
* mapper对象
* @param mapper
* @return
*/
public MyBatisFlexBatchItemWriterBuilder<T> mapper(BaseMapper<T> mapper) {
this.mapper = mapper;
return this;
}
/**
* 是否更新标志位
* @param assertUpdates
* @return
*/
public MyBatisFlexBatchItemWriterBuilder<T> assertUpdates(boolean assertUpdates) {
this.assertUpdates = assertUpdates;
return this;
}
/**
* 构建写入工具
* @return
*/
public MybatisFlexBatchItemWriter<T> build() {
MybatisFlexBatchItemWriter<T> writer = new MybatisFlexBatchItemWriter<>();
writer.setMapper(this.mapper);
Optional.ofNullable(this.assertUpdates).ifPresent(writer::setAssertUpdates);
return writer;
}
}

View File

@ -0,0 +1,88 @@
package com.mybatisflex.spring.batch.builder;
import com.mybatisflex.spring.batch.MyBatisFlexCursorItemReader;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryWrapper;
import org.mybatis.spring.batch.MyBatisCursorItemReader;
import java.util.Optional;
/**
* MyBatisCursorItemReader 构造工具
* @author zhangjian
* @param <T>
*/
public class MyBatisFlexCursorItemReaderBuilder<T> {
/**
* mapper对象
*/
private BaseMapper<T> mapper;
/**
* 查询条件对象
*/
private QueryWrapper queryWrapper;
private Boolean saveState;
/**
* 最大读取行数
*/
private Integer maxItemCount;
/**
* 设置mapper对象
* @param mapper
* @return
*/
public MyBatisFlexCursorItemReaderBuilder<T> mapper(BaseMapper<T> mapper) {
this.mapper = mapper;
return this;
}
/**
* 设置查询条件
* @param queryWrapper
* @return
*/
public MyBatisFlexCursorItemReaderBuilder<T> queryWrapper(QueryWrapper queryWrapper) {
this.queryWrapper = queryWrapper;
return this;
}
/**
* 保存状态标志位
* @param saveState
* @return
*/
public MyBatisFlexCursorItemReaderBuilder<T> saveState(boolean saveState) {
this.saveState = saveState;
return this;
}
/**
* 数据读取最大行数
* @param maxItemCount
* @return
*/
public MyBatisFlexCursorItemReaderBuilder<T> maxItemCount(int maxItemCount) {
this.maxItemCount = maxItemCount;
return this;
}
/**
* Returns a fully built {@link MyBatisFlexCursorItemReader}.
*
* @return the reader
*/
public MyBatisFlexCursorItemReader<T> build() {
MyBatisFlexCursorItemReader<T> reader = new MyBatisFlexCursorItemReader<>();
reader.setMapper(this.mapper);
reader.setQueryWrapper(this.queryWrapper);
Optional.ofNullable(this.saveState).ifPresent(reader::setSaveState);
Optional.ofNullable(this.maxItemCount).ifPresent(reader::setMaxItemCount);
return reader;
}
}

View File

@ -0,0 +1,107 @@
package com.mybatisflex.spring.batch.builder;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.batch.MybatisFlexPagingItemReader;
import java.util.Optional;
/**
* MybatisFlexPagingItemReader 构造工具
* @author zhangjian
* @param <T>
*/
public class MyBatisFlexPagingItemReaderBuilder<T> {
/**
* mapper对象
*/
private BaseMapper<T> mapper;
/**
* 查询条件对象
*/
private QueryWrapper queryWrapper;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 保存状态标志位
*/
private Boolean saveState;
/**
* 数据最大读取数量
*/
private Integer maxItemCount;
/**
* 设置mapper
* @param mapper
* @return
*/
public MyBatisFlexPagingItemReaderBuilder<T> mapper(BaseMapper<T> mapper) {
this.mapper = mapper;
return this;
}
/**
* 设置查询条件
* @param queryWrapper
* @return
*/
public MyBatisFlexPagingItemReaderBuilder<T> queryWrapper(QueryWrapper queryWrapper) {
this.queryWrapper = queryWrapper;
return this;
}
/**
* 分页大小
* @param pageSize
* @return
*/
public MyBatisFlexPagingItemReaderBuilder<T> pageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
/**
* 是否更新状态标志位
* @param saveState
* @return
*/
public MyBatisFlexPagingItemReaderBuilder<T> saveState(boolean saveState) {
this.saveState = saveState;
return this;
}
/**
* Configure the max number of items to be read.
* default Integer.Max_Value
* @param maxItemCount
* @return
*/
public MyBatisFlexPagingItemReaderBuilder<T> maxItemCount(int maxItemCount) {
this.maxItemCount = maxItemCount;
return this;
}
/**
* Returns a fully built {@link MybatisFlexPagingItemReader}.
*
* @return the reader
*/
public MybatisFlexPagingItemReader<T> build() {
MybatisFlexPagingItemReader<T> reader = new MybatisFlexPagingItemReader<>();
reader.setMapper(this.mapper);
reader.setQueryWrapper(this.queryWrapper);
Optional.ofNullable(this.pageSize).ifPresent(reader::setPageSize);
Optional.ofNullable(this.saveState).ifPresent(reader::setSaveState);
Optional.ofNullable(this.maxItemCount).ifPresent(reader::setMaxItemCount);
return reader;
}
}

View File

@ -42,6 +42,12 @@
<version>1.2.18</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-jdbc</artifactId>-->

View File

@ -80,6 +80,12 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-test</artifactId>
<version>1.10.9</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

13
pom.xml
View File

@ -76,6 +76,7 @@
<HikariCP.version>4.0.3</HikariCP.version>
<spring.version>5.3.27</spring.version>
<spring-batch.version>4.3.10</spring-batch.version>
<spring-boot.version>2.7.11</spring-boot.version>
<solon.version>3.0.1</solon.version>
<loveqq.version>1.1.0-java8</loveqq.version>
@ -179,6 +180,18 @@
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
<version>${spring-batch.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-infrastructure</artifactId>
<version>${spring-batch.version}</version>
</dependency>
<!--for test-->
<dependency>
<groupId>junit</groupId>