目录
- 前言
- 实现效果
- 批量新增插件的配置
- updateBatchById实现
- 自定义方法枚举
- 自定义批量更新方法
- 自定义更新wrapper
- 参照批量新增把方法添加到方法列表
- 测试updateBatchById
- 总结
前言
在使用mybatis-plus过程中,有很多插件都特别优秀,不仅使我们代码更加优雅,也提升了效率。
其中有个批量插入的插件insertBatchSomeColumn使用起来也挺方便的,但是批量更新一直没有官方插件,网络上面也没有找到靠谱的,于是就参照mybatis-plus这些官方的方法自定义了一个批量更新的方法。
实现效果
案例:用户排序

最终更新语句:
UPDATE sys_user SET user_order = CASE id WHEN 1 THEN 1 WHEN 2 THEN 2 WHEN 3 THEN 3 WHEN 4 THEN 4 END WHERE tenant_id = 1 AND id IN (1,2,3,4)
批量新增插件的配置
定义一个自己的BaseMapper继承自mybatis-plus的BaseMapper,声明批量新增方法,如下:
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 批量插入
*
* @param entityList 实体列表
* @return 影响行数
*/
int insertBatchSomeColumn(Collection<T> entityList);
}
把批量新增方法添加到方法列表中:
/**
* 通用方法注入
*/
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
// 添加批量新增方法
methodList.add(new InsertBatchSomeColumn());
return methodList;
}
}
MybatisPlusConfig配置中注入bean:
@Bean
public MySqlInjector mySqlInjector() {
return new MySqlInjector();
}
业务Mapper继承自自定义的MyBaseMapper,则就可以使用批量新增方法了。
下面进入正题
updateBatchById实现
自定义方法枚举
参照官方的SqlMethod,创建枚举MySqlMethod,并定义批量更新方法,如下:
public enum MySqlMethod {
UPDATE_BATCH_BY_ID("updateBatchById", "通过主键批量更新数据", "<script>UPDATE %s \n%s \nWHERE %s IN %s\n</script>");
private final String method;
private final String desc;
private final String sql;
MySqlMethod(String method, String desc, String sql) {
this.method = method;
this.desc = desc;
this.sql = sql;
}
public String getMethod() {
return this.method;
}
public String getDesc() {
return this.desc;
}
public String getSql() {
return this.sql;
}
}
自定义批量更新方法
定义UpdateBatchById继承自AbstractMethod,实现其抽象方法injectMappedStatement,功能就是拼接sql,具体实现如下:
/**
* 通过ID批量更新
*/
public class UpdateBatchById extends AbstractMethod {
private static final long serialVersionUID = 4198102405483580486L;
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
MySqlMethod sqlMethod = MySqlMethod.UPDATE_BATCH_BY_ID;
String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), this.sqlSet(tableInfo), tableInfo.getKeyColumn(), this.sqlIn(tableInfo.getKeyProperty()));
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource);
}
private String sqlSet(TableInfo tableInfo) {
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
StringBuilder sb = new StringBuilder();
for (TableFieldInfo fieldInfo : fieldList) {
sb.append("<if test=\"ew.updateFields.contains("").append(fieldInfo.getColumn()).append("")\">")
.append(fieldInfo.getColumn()).append(" =\n")
.append("CASE ").append(tableInfo.getKeyColumn()).append("\n")
.append("<foreach collection=\"list\" item=\"et\" >\n")
.append("WHEN #{et.").append(tableInfo.getKeyProperty()).append("} THEN #{et.").append(fieldInfo.getProperty()).append("}\n")
.append("</foreach>\n").append("END ,\n")
.append("</if>\n");
}
return "<set>\n" + sb + "</set>";
}
private String sqlIn(String keyProperty) {
StringBuilder sb = new StringBuilder();
sb.append("<foreach collection=\"list\" item=\"et\" separator=\",\" open=\"(\" close=\")\">\n")
.append("#{et.").append(keyProperty).append("}")
.append("</foreach>\n");
return sb.toString();
}
}
到了这一步已经能够基本实现功能了,但是无法控制需要更新的字段,继续看下面。
自定义更新wrapper
自定义UpdateBatchWrapper继承自AbstractLambdaWrapper,此类主要为updateFields属性设置值,拼接sql的时候只对设置的属性更新,其他属性不变。
public class UpdateBatchWrapper<T> extends AbstractLambdaWrapper<T, UpdateBatchWrapper<T>> {
private static final long serialVersionUID = 114684162001472707L;
/**
* 需要更新的字段
*/
private List<String> updateFields = null;
@Override
protected UpdateBatchWrapper<T> instance() {
this.updateFields = new ArrayList<>();
return this;
}
/**
* 关键代码,为属性设置值
*/
@SafeVarargs
public final UpdateBatchWrapper<T> setUpdateFields(SFunction<T, ?>... columns) {
this.updateFields = Arrays.asList(columnsToString(columns).split(","));
return this;
}
public List<String> getUpdateFields() {
return updateFields;
}
}
参照批量新增把方法添加到方法列表
MyBaseMapper增加配置:
/**
* 通过ID批量更新数据
*
* @param entityList 实体列表
* @return 影响行数
*/
int updateBatchById(@Param("list") Collection<T> entityList, @Param("ew") Wrapper<T> updateWrapper);
MySqlInjector增加配置:
// 添加批量更新方法 methodList.add(new UpdateBatchById());
测试updateBatchById
创建一个接口saveUserOrder实现用户排序,进而检查批量更新方法。
controller层
@PostMapping("saveUserOrder")
@ApiOperation("用户排序")
public Result saveUserOrder(@RequestBody List<OrderUserSO> soList) {
sysService.saveUserOrder(soList);
return Result.success();
}
service层
@Override
public void saveUserOrder(List<OrderUserSO> soList) {
// 业务实体转换为数据库实体
List<SysUser> userList = JSONUtil.toList(JSONUtil.toJsonStr(soList), SysUser.class);
// 批量更新-设置更新字段为userOrder
sysUserMapper.updateBatchById(userList,
new UpdateBatchWrapper<SysUser>()
.setUpdateFields(SysUser::getUserOrder));
}
OrderUserSO实体
@Data
@ApiModel("用户排序业务实体")
public class OrderUserSO implements Serializable {
private static final long serialVersionUID = 509541044282315352L;
@ApiModelProperty(value = "用户ID", required = true)
@NotNull
private Integer id;
@ApiModelProperty(value = "用户顺序", required = true)
@NotNull
private Integer userOrder;
}
见证奇迹的时刻到了…去文章开头见证奇迹吧。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

评论(0)