mybatis-plus自定义sql模板,自定义批量更新或插入
文章目录背景解决办法自定义步骤3.1 定义类似mapper.xml模板3.2 在springboot 启动时动态加载自定义的sql3.3 自定义自己的baseMapper,替换官方的baseMapper3.4 自定义自己的service,替换官方的serviceImpl4 使用背景mybatis-plus 增强了mybatis,在使用mybatis-plus连接sql,经常会遇到以下问题1、需要自
文章目录
背景
mybatis-plus 增强了mybatis,但使用时,也会遇到以下问题
1、需要自定义主键
2、不能按照联合主键进行批量更新,如以下sql
insert into `test` (`id`,`plan_id``) VALUES (1,2),(3,4) ON DUPLICATE KEY UPDATE id=values(id),plan_id=values(plan_id)3、当使用mybatis-plus自带的saveOrUpdateBatch时,性能也不是很好
解决办法
自定义模板,在mybatis-plus 3.0以上,官方已经提供了一种解决方案 sql注入器
官方参考:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-deluxe
自定义步骤
3.1 定义类似mapper.xml模板
下面代码就干了一件事,根据tableinfo动态生成xml版的sql.生成后就不用手动去写了
insert into
test(id,`plan_id``) VALUES (1,2),(3,4)
ON DUPLICATE KEY UPDATE
id=values(id),plan_id=values(plan_id)
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.springframework.util.StringUtils;
public class MysqlInsertOrUpdateBath extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s ON DUPLICATE KEY UPDATE %s</script>";
final String tableName = tableInfo.getTableName();
final String filedSql = prepareFieldSql(tableInfo);
final String modelValuesSql = prepareModelValuesSql(tableInfo);
final String duplicateKeySql =prepareDuplicateKeySql(tableInfo);
final String sqlResult = String.format(sql, tableName, filedSql, modelValuesSql,duplicateKeySql);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, "mysqlInsertOrUpdateBath", sqlSource, new NoKeyGenerator(), null, null);
}
/**
* 准备ON DUPLICATE KEY UPDATE sql
* @param tableInfo
* @return
*/
private String prepareDuplicateKeySql(TableInfo tableInfo) {
final StringBuilder duplicateKeySql = new StringBuilder();
if(!StringUtils.isEmpty(tableInfo.getKeyColumn())) {
duplicateKeySql.append(tableInfo.getKeyColumn()).append("=(").append(tableInfo.getKeyColumn()).append("),");
}
tableInfo.getFieldList().forEach(x -> {
duplicateKeySql.append(x.getColumn())
.append("=(")
.append(x.getColumn())
.append("),");
});
duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
return duplicateKeySql.toString();
}
/**
* 准备属性名
* @param tableInfo
* @return
*/
private String prepareDuplicateKeySql(TableInfo tableInfo) {
final StringBuilder duplicateKeySql = new StringBuilder();
if(!StringUtils.isEmpty(tableInfo.getKeyColumn())) {
duplicateKeySql.append(tableInfo.getKeyColumn()).append("=(").append(tableInfo.getKeyColumn()).append("),");
}
tableInfo.getFieldList().forEach(x -> {
duplicateKeySql.append(x.getColumn())
.append("=VALUES(")
.append(x.getColumn())
.append("),");
});
duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
return duplicateKeySql.toString();
}
private String prepareModelValuesSql(TableInfo tableInfo){
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
if(!StringUtils.isEmpty(tableInfo.getKeyProperty())) {
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
}
tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
return valueSql.toString();
}
}
3.2 在springboot 启动时动态加载自定义的sql
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class MysqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList() {
List<AbstractMethod> methodList = super.getMethodList();
methodList.add(new MysqlInsertOrUpdateBath());
return methodList;
}
}
3.3 自定义自己的baseMapper,替换官方的baseMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* 自定义的mapper
* @param <T>
*/
public interface BridgeBaseMapper<T> extends BaseMapper<T> {
int mysqlInsertOrUpdateBath(List<T> list);
}
3.4 自定义自己的service,替换官方的serviceImpl
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
public class BridgeBaseService1<M extends BridgeBaseMapper<T>, T> extends ServiceImpl<M, T> {
//这快就调用了刚才自定义的mapper
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize){
Assert.notEmpty(entityList, "error: entityList must not be empty");
List<T> objs = Lists.newArrayList(entityList);
List<List<T>> partitions = Lists.partition(objs, batchSize);
for(List<T> list:partitions) {
this.baseMapper.mysqlInsertOrUpdateBath(list);
}
return true;
}
}
4 使用
业务的service继承自定义的BridgeBaseService1.就和继承官方的serviceImpl一样酸爽
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)