From ea03a5f3dfb7ee3d07706e891b886e3a0ab043c4 Mon Sep 17 00:00:00 2001 From: zhj149 Date: Mon, 28 Apr 2025 13:47:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0SpringBatch=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81,Linux=E4=B8=8B=E5=BC=80=E5=8F=91,=E6=9C=89=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=86=99=E5=90=8D=E7=A7=B0=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?.=E6=89=80=E4=BB=A5AccountMapper=E6=94=B9=E4=BA=86=E4=B8=8B?= =?UTF-8?q?=E5=90=8D=E5=AD=97.=20=E6=97=A0=E6=B3=95install=E5=88=B0?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E6=B5=8B=E8=AF=95,=E6=B2=A1=E5=86=99?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mybatis-flex-spring/pom.xml | 10 ++ .../batch/MyBatisFlexCursorItemReader.java | 98 ++++++++++++++++ .../batch/MybatisFlexBatchItemWriter.java | 76 +++++++++++++ .../batch/MybatisFlexPagingItemReader.java | 84 ++++++++++++++ .../MyBatisFlexBatchItemWriterBuilder.java | 55 +++++++++ .../MyBatisFlexCursorItemReaderBuilder.java | 88 ++++++++++++++ .../MyBatisFlexPagingItemReaderBuilder.java | 107 ++++++++++++++++++ .../mybatis-flex-spring-boot-test/pom.xml | 6 + .../{accountMapper.xml => AccountMapper.xml} | 0 .../mybatis-flex-spring-cloud-test/pom.xml | 6 + pom.xml | 13 +++ 11 files changed, 543 insertions(+) create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MyBatisFlexCursorItemReader.java create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexBatchItemWriter.java create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexPagingItemReader.java create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexBatchItemWriterBuilder.java create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexCursorItemReaderBuilder.java create mode 100644 mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexPagingItemReaderBuilder.java rename mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/mapper/{accountMapper.xml => AccountMapper.xml} (100%) diff --git a/mybatis-flex-spring/pom.xml b/mybatis-flex-spring/pom.xml index e4744a1e..88cc2f7e 100644 --- a/mybatis-flex-spring/pom.xml +++ b/mybatis-flex-spring/pom.xml @@ -40,6 +40,16 @@ spring-jdbc + + org.springframework.batch + spring-batch-core + + + + org.springframework.batch + spring-batch-infrastructure + + com.github.gavlyukovskiy datasource-decorator-spring-boot-autoconfigure diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MyBatisFlexCursorItemReader.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MyBatisFlexCursorItemReader.java new file mode 100644 index 00000000..fd85fc63 --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MyBatisFlexCursorItemReader.java @@ -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 extends AbstractItemCountingItemStreamItemReader + implements InitializingBean { + + /** + * 当前的mapper + */ + private BaseMapper mapper; + + /** + * 拼接的入参列表 + */ + private QueryWrapper queryWrapper; + + /** + * + */ + private Cursor cursor; + + /** + * + */ + private Iterator cursorIterator; + + public MyBatisFlexCursorItemReader() { + setName(getShortName(MyBatisFlexCursorItemReader.class)); + } + + /** + * 当前的mapper对象 + * @param mapper + */ + public void setMapper(BaseMapper 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."); + } + +} diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexBatchItemWriter.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexBatchItemWriter.java new file mode 100644 index 00000000..dd90a6ea --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexBatchItemWriter.java @@ -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 + */ +public class MybatisFlexBatchItemWriter implements ItemWriter, InitializingBean { + + private static final Logger LOGGER = LoggerFactory.getLogger(MybatisFlexBatchItemWriter.class); + + private BaseMapper 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 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 items) { + + if (!items.isEmpty()) { + LOGGER.debug(() -> "Executing batch with " + items.size() + " items."); + int results = this.mapper.insertBatch((List) items); + + if (assertUpdates) { + if (results != items.size()) { + throw new EmptyResultDataAccessException( + "Items.size + " + items.size() + " doesn't match the number of updated rows: " + results, 1); + + } + } + } + } +} diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexPagingItemReader.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexPagingItemReader.java new file mode 100644 index 00000000..22b797c4 --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/MybatisFlexPagingItemReader.java @@ -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 实体类型 + */ +public class MybatisFlexPagingItemReader extends AbstractPagingItemReader { + + /** + * 当前的mapper + */ + private BaseMapper mapper; + + /** + * 拼接的入参列表 + */ + private QueryWrapper queryWrapper; + + public MybatisFlexPagingItemReader() { + setName(getShortName(MyBatisPagingItemReader.class)); + } + + /** + * 当前的mapper对象 + * @param mapper + */ + public void setMapper(BaseMapper 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 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 paginate = mapper.paginate(itemIndex + 1, getPageSize(), queryWrapper); + results.addAll(paginate.getRecords()); + } +} diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexBatchItemWriterBuilder.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexBatchItemWriterBuilder.java new file mode 100644 index 00000000..55892aa7 --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexBatchItemWriterBuilder.java @@ -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 { + + /** + * mapper对象 + */ + private BaseMapper mapper; + + private Boolean assertUpdates; + + /** + * mapper对象 + * @param mapper + * @return + */ + public MyBatisFlexBatchItemWriterBuilder mapper(BaseMapper mapper) { + this.mapper = mapper; + return this; + } + + /** + * 是否更新标志位 + * @param assertUpdates + * @return + */ + public MyBatisFlexBatchItemWriterBuilder assertUpdates(boolean assertUpdates) { + this.assertUpdates = assertUpdates; + return this; + } + + /** + * 构建写入工具 + * @return + */ + public MybatisFlexBatchItemWriter build() { + MybatisFlexBatchItemWriter writer = new MybatisFlexBatchItemWriter<>(); + writer.setMapper(this.mapper); + Optional.ofNullable(this.assertUpdates).ifPresent(writer::setAssertUpdates); + return writer; + } + +} diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexCursorItemReaderBuilder.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexCursorItemReaderBuilder.java new file mode 100644 index 00000000..bc3d7b6d --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexCursorItemReaderBuilder.java @@ -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 + */ +public class MyBatisFlexCursorItemReaderBuilder { + + /** + * mapper对象 + */ + private BaseMapper mapper; + + /** + * 查询条件对象 + */ + private QueryWrapper queryWrapper; + + private Boolean saveState; + + /** + * 最大读取行数 + */ + private Integer maxItemCount; + + /** + * 设置mapper对象 + * @param mapper + * @return + */ + public MyBatisFlexCursorItemReaderBuilder mapper(BaseMapper mapper) { + this.mapper = mapper; + return this; + } + + /** + * 设置查询条件 + * @param queryWrapper + * @return + */ + public MyBatisFlexCursorItemReaderBuilder queryWrapper(QueryWrapper queryWrapper) { + this.queryWrapper = queryWrapper; + return this; + } + + /** + * 保存状态标志位 + * @param saveState + * @return + */ + public MyBatisFlexCursorItemReaderBuilder saveState(boolean saveState) { + this.saveState = saveState; + return this; + } + + /** + * 数据读取最大行数 + * @param maxItemCount + * @return + */ + public MyBatisFlexCursorItemReaderBuilder maxItemCount(int maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + /** + * Returns a fully built {@link MyBatisFlexCursorItemReader}. + * + * @return the reader + */ + public MyBatisFlexCursorItemReader build() { + MyBatisFlexCursorItemReader 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; + } + +} diff --git a/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexPagingItemReaderBuilder.java b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexPagingItemReaderBuilder.java new file mode 100644 index 00000000..50ab7357 --- /dev/null +++ b/mybatis-flex-spring/src/main/java/com/mybatisflex/spring/batch/builder/MyBatisFlexPagingItemReaderBuilder.java @@ -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 + */ +public class MyBatisFlexPagingItemReaderBuilder { + + /** + * mapper对象 + */ + private BaseMapper mapper; + + /** + * 查询条件对象 + */ + private QueryWrapper queryWrapper; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 保存状态标志位 + */ + private Boolean saveState; + + /** + * 数据最大读取数量 + */ + private Integer maxItemCount; + + /** + * 设置mapper + * @param mapper + * @return + */ + public MyBatisFlexPagingItemReaderBuilder mapper(BaseMapper mapper) { + this.mapper = mapper; + return this; + } + + /** + * 设置查询条件 + * @param queryWrapper + * @return + */ + public MyBatisFlexPagingItemReaderBuilder queryWrapper(QueryWrapper queryWrapper) { + this.queryWrapper = queryWrapper; + return this; + } + + /** + * 分页大小 + * @param pageSize + * @return + */ + public MyBatisFlexPagingItemReaderBuilder pageSize(int pageSize) { + this.pageSize = pageSize; + return this; + } + + /** + * 是否更新状态标志位 + * @param saveState + * @return + */ + public MyBatisFlexPagingItemReaderBuilder 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 maxItemCount(int maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + /** + * Returns a fully built {@link MybatisFlexPagingItemReader}. + * + * @return the reader + */ + public MybatisFlexPagingItemReader build() { + MybatisFlexPagingItemReader 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; + } + +} diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml index 0ebbcba4..b8d07fcc 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml @@ -42,6 +42,12 @@ 1.2.18 + + org.springframework.boot + spring-boot-starter-batch + ${spring-boot.version} + + diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/mapper/accountMapper.xml b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/mapper/AccountMapper.xml similarity index 100% rename from mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/mapper/accountMapper.xml rename to mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/mapper/AccountMapper.xml diff --git a/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml index 4bc52b9a..522dfa12 100644 --- a/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml @@ -80,6 +80,12 @@ spring-boot-starter-test test + + com.mybatis-flex + mybatis-flex-spring-test + 1.10.9 + compile + diff --git a/pom.xml b/pom.xml index 987dd8d9..3f7b934a 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,7 @@ 4.0.3 5.3.27 + 4.3.10 2.7.11 3.0.1 1.1.0-java8 @@ -179,6 +180,18 @@ ${spring-boot.version} + + org.springframework.batch + spring-batch-core + ${spring-batch.version} + + + + org.springframework.batch + spring-batch-infrastructure + ${spring-batch.version} + + junit