sql代码批量生成工具
1、思路原理
背景:即兴想借用mybatis-plus的api生成sql。调用mybatis-plus的sql执行接口,即可批量生成sql执行脚本。
原理:执行sql语法的时候使用拦截器拦截sql session执行,获取到最终sql并使用io流输出到本地文件中。
核心代码:com.fg.core.ReplacePlaceholderInnerInterceptor
核心执行逻辑:
- com.fg.core.ReplacePlaceholderInnerInterceptor
- 动态表名插件
- 获取boundSql进行占位符替换
- 抛出NormalTerminationException正常退出的异常,保证sql不会最终的执行
- com.fg.core.MapperExceptionAspect
- 环绕api的执行方法,捕获正常退出的方法,并返回对应类型的空返回
2、业务背景
痛点1
业务甩几万甚至几十万数据,要我们确定库内是否有该数据。在没有数仓场景下我们只能使用sql去线上库查,但需要避免大批量查询打爆线上库或者库工具只支持有限的查询。因此该工具支持使用mybatis-plus的api批量生成sql。
痛点2
业务说这几十万数据,库内有的需要订正成逻辑删除状态,且每次只有删除60条才能避免对数据库照成影响,且该数量庞大,就需要工具生成。
例如我们需要生成以下格式sql
update test_table
set is_delete=1
where (
(姓名 = '张三' and gender = '男' and focus = '无' and age = '33')
or (姓名 = '李四' and gender = '男' and focus = '好对象' and age = '23')
or (姓名 = '王妹妹' and gender = '女' and focus = '特别关注' and age = '22')
。。。
以下省略60个or
。。。
)
3、使用方法
继承com.fg.generaltor.BaseGeneralGenerator,核心方法均在该类里面。将实现类注入spring容器,重写process方法,内部可以使用generalTableMapper调用mybatis-plus的api,即可生成sql脚本,你也可以封装成web接口。
样例类:
- com.fg.generaltor.SimpleTestGenerator
- com.fg.generaltor.TestGenerator
你可以自己运行一次,即可通过样例类生成其对应的sql脚本尝鲜。
默认输出sql文件位置
默认输出文件位置在当前jar包目录下,如果你是idea运行的,路径如下:target/classes/fileName.sql
例:com.fg.generaltor.TestGenerator。
import cn.hutool.core.text.csv.CsvUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fg.entity.GeneralTable;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
* @author: 王富贵
* @description: 测试sql生成器
* @createTime: 2024年04月20日 23:31:41
*/
@Component
public class TestGenerator extends BaseGenerator {
@Override
protected void setTableName() {
super.setTableName("我是动态表哦");
}
@Override
public void process() {
// 测试1
// 设置每批数量
setBatchCount(3);
setOutPutFileName("TestGenerator");
setTableName("test_generator_table_name");
List<Map<String, String>> userMapsList;
try {
userMapsList = CsvUtil.getReader().readMapList(new FileReader(ResourceUtils.getFile("classpath:test.csv")));
} catch (IOException e) {
throw new RuntimeException(e);
}
/* 目标格式
update test_table set is_delete = 1
where (
(id = '1003' and 姓名 = '张三' and gender = '男' and focus = '无' and age = '33')
or (id = '2006' and 姓名 = '李四' and gender = '男' and focus = '好对象' and age = '23')
or (id = '3009' and 姓名 = '王妹妹' and gender = '女' and focus = '特别关注' and age = '22')
)
*/
batchUpdate(userMapsList,
new BiConsumer<UpdateWrapper<GeneralTable>, List<Map<String, String>>>() {
@Override
public void accept(UpdateWrapper<GeneralTable> updateWrapper, List<Map<String, String>> maps) {
updateWrapper.set("is_delete", 1);
}
},
new BiConsumer<UpdateWrapper<GeneralTable>, Map<String, String>>() {
@Override
public void accept(UpdateWrapper<GeneralTable> updateWrapper, Map<String, String> stringStringMap) {
updateWrapper.or(updateWrapperTmp -> updateWrapperTmp.allEq(stringStringMap));
}
});
/* 目标格式
select id,name,age,email from test_table where (id in (1003,2006,3009))
*/
batchSelect(userMapsList,
new BiConsumer<QueryWrapper<GeneralTable>, List<Map<String, String>>>() {
@Override
public void accept(QueryWrapper<GeneralTable> queryWrapper, List<Map<String, String>> maps) {
List<Long> ids = maps.stream()
.map(map -> map.get("id")) // 提取每个 Map 对象的 id 值
.filter(id -> id != null && id.matches("\\d+")) // 过滤非空且符合数字格式的 id
.map(Long::parseLong) // 将字符串 id 转换为 Long 类型
.collect(Collectors.toList()); // 收集成一个 List<Long>
queryWrapper.in("id", ids);
}
},
(BiConsumer<QueryWrapper<GeneralTable>, Map<String, String>>) (queryWrapper, userMaps) -> {
}
);
/**
* 测试2
*/
// 设置每批数量
setBatchCount(60);
try {
userMapsList = CsvUtil.getReader().readMapList(new FileReader(ResourceUtils.getFile("classpath:test.csv")));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
batchUpdate(userMapsList,
new BiConsumer<UpdateWrapper<GeneralTable>, List<Map<String, String>>>() {
@Override
public void accept(UpdateWrapper<GeneralTable> updateWrapper, List<Map<String, String>> maps) {
updateWrapper.set("is_delete", 1);
}
},
new BiConsumer<UpdateWrapper<GeneralTable>, Map<String, String>>() {
@Override
public void accept(UpdateWrapper<GeneralTable> updateWrapper, Map<String, String> stringStringMap) {
updateWrapper.or(updateWrapperTmp -> updateWrapperTmp.allEq(stringStringMap));
}
});
/**
* 测试3
*/
// 动态表名实现表名变更
setTableName("tools");
QueryWrapper<GeneralTable> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", 1).eq("email_name", "li");
generalTableMapper.delete(queryWrapper);
/**
* 测试4
*/
UpdateWrapper<GeneralTable> updateWrapper = new UpdateWrapper<>();
ArrayList<Integer> ids = new ArrayList<>();
for (int i = 0; i < 5; i++) {
ids.add(i);
}
updateWrapper.in("id", ids);
updateWrapper.set("name", "富??贵");
generalTableMapper.update(updateWrapper);
}
}
评论区