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
下面代码就干了一件事,根据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 = "";
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("");
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(" ");
return valueSql.toString();
}
}
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 getMethodList() {
List methodList = super.getMethodList();
methodList.add(new MysqlInsertOrUpdateBath());
return methodList;
}
}
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* 自定义的mapper
* @param
*/
public interface BridgeBaseMapper extends BaseMapper {
int mysqlInsertOrUpdateBath(List list);
}
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, T> extends ServiceImpl {
//这快就调用了刚才自定义的mapper
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection entityList, int batchSize){
Assert.notEmpty(entityList, "error: entityList must not be empty");
List objs = Lists.newArrayList(entityList);
List> partitions = Lists.partition(objs, batchSize);
for(List list:partitions) {
this.baseMapper.mysqlInsertOrUpdateBath(list);
}
return true;
}
}
业务的service继承自定义的BridgeBaseService1.就和继承官方的serviceImpl一样酸爽