前言
在使用mybatis-plus过程中,有很多插件都特别优秀,不仅使我们代码更加优雅,也提升了效率。
其中有个批量插入的插件insertBatchSomeColumn使用起来也挺方便的,但是批量更新一直没有官方插件,网络上面也没有找到靠谱的,于是就参照mybatis-plus这些官方的方法自定义了一个批量更新的方法。
实现效果
案例:用户排序
最终更新语句:
1 2 3 4 5 6 7 8 9 10 11 | 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,声明批量新增方法,如下:
1 2 3 4 5 6 7 8 9 | public interface MyBaseMapper extends BaseMapper { /** * 批量插入 * * @param entityList 实体列表 * @return 影响行数 */ int insertBatchSomeColumn(Collection entityList); } |
把批量新增方法添加到方法列表中:
1 2 3 4 5 6 7 8 9 10 11 12 | /** * 通用方法注入 */ public class MySqlInjector extends DefaultSqlInjector { @Override public List getMethodList(Class> mapperClass) { List methodList = super .getMethodList(mapperClass); // 添加批量新增方法 methodList.add( new InsertBatchSomeColumn()); return methodList; } } |
MybatisPlusConfig配置中注入bean:
1 2 3 4 | @Bean public MySqlInjector mySqlInjector() { return new MySqlInjector(); } |
业务Mapper继承自自定义的MyBaseMapper,则就可以使用批量新增方法了。
下面进入正题
updateBatchById实现
自定义方法枚举
参照官方的SqlMethod,创建枚举MySqlMethod,并定义批量更新方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public enum MySqlMethod { UPDATE_BATCH_BY_ID( "updateBatchById" , "通过主键批量更新数据" , "UPDATE %s n%s nWHERE %s IN %sn" ); 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,具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /** * 通过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 fieldList = tableInfo.getFieldList(); StringBuilder sb = new StringBuilder(); for (TableFieldInfo fieldInfo : fieldList) { sb.append( "" ) .append(fieldInfo.getColumn()).append( " =n" ) .append( "CASE " ).append(tableInfo.getKeyColumn()).append( "n" ) .append( "n" ) .append( "WHEN #{et." ).append(tableInfo.getKeyProperty()).append( "} THEN #{et." ).append(fieldInfo.getProperty()).append( "}n" ) .append( "n" ).append( "END ,n" ) .append( "n" ); } return "n" + sb + "" ; } private String sqlIn(String keyProperty) { StringBuilder sb = new StringBuilder(); sb.append( "n" ) .append( "#{et." ).append(keyProperty).append( "}" ) .append( "n" ); return sb.toString(); } } |
到了这一步已经能够基本实现功能了,但是无法控制需要更新的字段,继续看下面。
自定义更新wrapper
自定义UpdateBatchWrapper继承自AbstractLambdaWrapper,此类主要为updateFields属性设置值,拼接sql的时候只对设置的属性更新,其他属性不变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class UpdateBatchWrapper extends AbstractLambdaWrapper> { private static final long serialVersionUID = 114684162001472707L; /** * 需要更新的字段 */ private List updateFields = null ; @Override protected UpdateBatchWrapper instance() { this .updateFields = new ArrayList(); return this ; } /** * 关键代码,为属性设置值 */ @SafeVarargs public final UpdateBatchWrapper setUpdateFields(SFunction... columns) { this .updateFields = Arrays.asList(columnsToString(columns).split( "," )); return this ; } public List getUpdateFields() { return updateFields; } } |
参照批量新增把方法添加到方法列表
MyBaseMapper增加配置:
1 2 3 4 5 6 7 | /** * 通过ID批量更新数据 * * @param entityList 实体列表 * @return 影响行数 */ int updateBatchById( @Param ( "list" ) Collection entityList, @Param ( "ew" ) Wrapper updateWrapper); |
MySqlInjector增加配置:
1 2 | // 添加批量更新方法 methodList.add( new UpdateBatchById()); |
测试updateBatchById
创建一个接口saveUserOrder实现用户排序,进而检查批量更新方法。
controller层
1 2 3 4 5 6 | @PostMapping ( "saveUserOrder" ) @ApiOperation ( "用户排序" ) public Result saveUserOrder( @RequestBody List soList) { sysService.saveUserOrder(soList); return Result.success(); } |
service层
1 2 3 4 5 6 7 8 9 | @Override public void saveUserOrder(List soList) { // 业务实体转换为数据库实体 List userList = JSONUtil.toList(JSONUtil.toJsonStr(soList), SysUser. class ); // 批量更新-设置更新字段为userOrder sysUserMapper.updateBatchById(userList, new UpdateBatchWrapper() .setUpdateFields(SysUser::getUserOrder)); } |
OrderUserSO实体
1 2 3 4 5 6 7 8 9 10 11 | @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; } |
见证奇迹的时刻到了…去文章开头见证奇迹吧。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持IT俱乐部。