mybatis-plus关于savebatch,saveorupdatebatch遇到的坑。。
⼀.背景
最近mybatis-plus框架的更新,让我们基础开发中如虎添翼。其中基本的增删改查,代码⽣成器想必⼤家⽤着那叫⼀个爽。本⼈在使⽤中,也遇到⼀些坑。⽐如savebatch,saveorupdatebatch,看着这不是批量新增,批量新增或更新嘛,看着api进⾏开发,感觉也太好⽤啦。开发完⼀测试,速度跟蜗⽜⼀样,针对⼤数据量真是⽆法忍受。在控制台上发现,怎么名义上是批量插⼊,还是⼀条⼀条的进⾏插⼊,难怪速度龟速。
⼆.解决办法
查阅⽹上资料,⼤体有两种解决⽅案:
(1).使⽤mybatis的xml,⾃⼰进⾏sql语句编写。该⽅法⼀个缺点是如果表的字段较多,有个⼏⼗个字段,写批量新增,批量新增修改的sql语句真是个噩梦。
INSERT INTO t
(id, age)
VALUES
(3, 28),
(4, 29)
ON DUPLICATE KEY UPDATE
id = VALUES(id),
age = VALUES(age);
(2)mybatis-plus 新添加了⼀个sql注⼊器,通过sql注⼊器可以实现批量新增,批量新增修改功能。⼀次注⼊,随时使⽤,使⽤极其⽅便。缺点就是项⽬启动时候,会进⾏sql注⼊器注册,稍微影响启动速度。
三.sql注⼊器实现批量更新,批量新增或更新功能
(1)⾃定义mapper接⼝,继承BaseMapper,定义实现的⽅法。
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 根Mapper,给表Mapper继承⽤的,可以⾃定义通⽤⽅法
* {@link BaseMapper}
* {@link sion.service.IService}
* {@link sion.service.impl.ServiceImpl}
*/
public interface RootMapper<T> extends BaseMapper<T> {
/**
* ⾃定义批量插⼊
* 如果要⾃动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之⼀    */
int insertBatch(@Param("list") List<T> list);
/**
* ⾃定义批量新增或更新
* 如果要⾃动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之⼀    */
int mysqlInsertOrUpdateBath(@Param("list") List<T> list);
}
(2)批量插⼊、批量新增或更新具体⽅法实现
批量插⼊具体⽅法实现如下:
import adata.TableInfo;
slf4j.Slf4j;
import org.utor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;批量更新sql语句
/**
* 批量插⼊⽅法实现
*/
@Slf4j
public class InsertBatchMethod extends AbstractMethod {
/**
* insert into user(id, name, age) values (1, "a", 17), (2, "b", 18);
<script>
insert into user(id, name, age) values
<foreach collection="list" item="item" index="index" open="(" separator="),(" close=")">
#{item.id}, #{item.name}, #{item.age}
</foreach>
</script>
*/
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
final String sql = "<script>insert into %s %s values %s</script>";
final String fieldSql = prepareFieldSql(tableInfo);
final String valueSql = prepareValuesSql(tableInfo);
final String sqlResult = String.format(sql, TableName(), fieldSql, valueSql);
log.debug("sqlResult----->{}", sqlResult);
SqlSource sqlSource = ateSqlSource(configuration, sqlResult, modelClass);
// 第三个参数必须和RootMapper的⾃定义⽅法名⼀致
return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);    }
private String prepareFieldSql(TableInfo tableInfo) {
StringBuilder fieldSql = new StringBuilder();
fieldSql.KeyColumn()).append(",");
fieldSql.Column()).append(",");
});
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
String();
}
private String prepareValuesSql(TableInfo tableInfo) {
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
valueSql.append("#{item.").KeyProperty()).append("},");
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
String();
}
}
批量插⼊或更新具体⽅法如下:
import injector.AbstractMethod;
import adata.TableInfo;
import org.utor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
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 = TableName();
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);
//System.out.println("savaorupdatesqlsql="+sqlResult);
SqlSource sqlSource = ateSqlSource(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.KeyColumn())) {
duplicateKeySql.KeyColumn()).append("=values(").KeyColumn()).append("),");
}
duplicateKeySql.Column())
.append("=values(")
.Column())
.append("),");
});
duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
String();
}
/
**
* 准备属性名
* @param tableInfo
* @return
*/
private String prepareFieldSql(TableInfo tableInfo) {
StringBuilder fieldSql = new StringBuilder();
fieldSql.KeyColumn()).append(",");
fieldSql.Column()).append(",");
});
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
fieldSql.insert(0, "(");
fieldSql.append(")");
String();
}
private String prepareModelValuesSql(TableInfo tableInfo){
final StringBuilder valueSql = new StringBuilder();
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
if(!StringUtils.KeyProperty())) {
valueSql.append("#{item.").KeyProperty()).append("},");
}
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append("</foreach>");
String();
}
}
(3)sql注⼊器实现
import injector.AbstractMethod;
import injector.DefaultSqlInjector;
import java.util.List;
/**
* ⾃定义⽅法SQL注⼊器
*/
public class CustomizedSqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加⽅法,保留mybatis plus⾃带⽅法,
* 可以先获取MethodList(),再添加add
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = MethodList(mapperClass);
methodList.add(new InsertBatchMethod());
methodList.add(new UpdateBatchMethod());
methodList.add(new MysqlInsertOrUpdateBath());
return methodList;
}
}
(4)在⾃⼰想使⽤的mapper上继承⾃定义的mapper.
import com.batisPlusExtend.RootMapper;
import com.sy.ity.InfMpmPds;
import adata.IPage;
import sion.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
@Component
public interface InfMpmPdsMapper extends RootMapper<InfMpmPds> {
IPage<InfMpmPds> selectPageList(Page page, @Param("infMpmPds") InfMpmPds infMpmPds);
}
(5)在controller或serviceImpi中引⼊mapper,使⽤⾃定义的⽅法。
>>>>>>>>>>>>>>>>>>>>引⼊mapper>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。