欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

mybatis-plus批量更新updateBatchById问题,

来源: javaer 分享于  点击 47780 次 点评:139

mybatis-plus批量更新updateBatchById问题,


目录
  • 前言
  • 实现效果
  • 批量新增插件的配置
  • 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(&quot;").append(fieldInfo.getColumn()).append("&quot;)\">")
                        .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;
    }

    见证奇迹的时刻到了…去文章开头见证奇迹吧。

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持3672js教程。

    您可能感兴趣的文章:
    • mybatis-plus的批量新增/批量更新以及问题
    • mybatis-plus批量更新太慢该如何解决详解
    • mybatis-plus update更新操作的三种方式(小结)
    相关栏目:

    用户点评