batch-insert-mybatis-plus

2 篇文章 0 订阅
前言

后台开发中,批量往数据库写数据是一个很常见的功能,下面就简单实现一下使用 mybatis-plus 来 batch 写入。

实现介绍
添加依赖

在项目的 pom.xml 中配置 mybatis-plus 以及 mysql 相关的依赖

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>
实现自定义的 mybatis-plus 方法

1、实现自定义的 mybatis-plus 方法 batchInsert。

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 java.util.concurrent.atomic.AtomicBoolean;

/**
 * Description:批量新增,要求所有非空字段必须有设置值
 *      参数:java.util.List<?> dataList
 *
 * @author fy
 * @version 1.0
 */
public class DemoBatchInsertMethod extends AbstractMethod {
    private static final long serialVersionUID = -5592924141208308506L;

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass,
                                                 TableInfo tableInfo) {
        /*
         * <p>
         * INSERT INTO tableName
         *      (id,name)
         * VALUES
         *   <foreach collection="dataList" item="data" open="(" close=")" index="index" separator="),(">
         *       #{data.id},#{data.name}
         *   </foreach>
         * </p>
         */
        String sql = "<script>\nINSERT INTO %s %s \nVALUES %s\n</script>";
        sql = String.format(sql, tableInfo.getTableName(),
                getFieldSql(tableInfo), getValueSql(tableInfo));
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass,
                "insertBatchDemo", sqlSource, new NoKeyGenerator(),
                tableInfo.getKeyProperty(), tableInfo.getKeyColumn());
    }

    private String getFieldSql(TableInfo tableInfo) {
        return "(" + tableInfo.getAllSqlSelect() + ")";
    }

    private String getValueSql(TableInfo tableInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("<foreach collection=\"dataList\" item=\"data\" open=\"(\" close=\")\"" +
                " index=\"index\" separator=\"),(\">\n");
        sb.append("#{data.").append(tableInfo.getKeyProperty()).append("},");
        AtomicBoolean isNotFirst = new AtomicBoolean(false);
        tableInfo.getFieldList().forEach(field -> {
            if (isNotFirst.get()) {
                sb.append(",");
            }
            sb.append("#{data.").append(field.getProperty()).append("}");
            isNotFirst.set(true);
        });
        sb.append("\n</foreach>");
        return sb.toString();
    }
}

2、实现自定义的 mybatis-plus 方法 batchInsertSelective。

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 java.util.concurrent.atomic.AtomicBoolean;

/**
 * Description:批量新增,只插入传入值的字段
 *      参数:java.util.List<?> dataList
 *
 * @author fy
 * @version 1.0
 */
public class DemoBatchInsertSelectiveMethod extends AbstractMethod {
    private static final long serialVersionUID = -5592924141208308506L;

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass,
                                                 TableInfo tableInfo) {
        /*
         * <p>
         * <foreach collection="dataList" item="data" index="index" separator=";">
         *      INSERT INTO tableName
         *        <trim prefix="(" suffix=")" suffixOverrides=",">
         *          <if test="data.id != null">
         *              id,
         *          </if>
         *          <if test="data.name != null">
         *              name,
         *          </if>
         *        </trim>
         *      VALUES
         *        <trim prefix="(" suffix=")" suffixOverrides=",">
         *          <if test="data.id != null">
         *              #{data.id},
         *          </if>
         *          <if test="data.name != null">
         *              #{data.name},
         *          </if>
         *        </trim>
         * </foreach>
         * </p>
         */
        String sql = "<script>\n<foreach collection=\"dataList\" item=\"data\"" +
                " index=\"index\" separator=\";\">\n" +
                "INSERT INTO %s %s VALUES %s \n" +
                "</foreach>\n</script>";
        sql = String.format(sql, tableInfo.getTableName(),
                getFieldSql(tableInfo), getValueSql(tableInfo));
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        // NoKeyGenerator:默认空实现,不需要对主键单独处理;
        // Jdbc3KeyGenerator:主要用于数据库的自增主键,比如 MySQL、PostgreSQL;
        // SelectKeyGenerator:主要用于数据库不支持自增主键的情况,比如 Oracle、DB2;
        return this.addInsertMappedStatement(mapperClass, modelClass,
                "insertBatchSelectiveDemo", sqlSource, new NoKeyGenerator(),
                tableInfo.getKeyProperty(), tableInfo.getKeyColumn());
    }

    private String getFieldSql(TableInfo tableInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
        sb.append("<if test=\"data.").append(tableInfo.getKeyProperty())
                .append(" != null\">").append(tableInfo.getKeyColumn())
                .append(",</if>");
        tableInfo.getFieldList().forEach(field ->
            sb.append("<if test=\"data.").append(field.getProperty())
                    .append(" != null\">").append(field.getColumn())
                    .append(",</if>")
        );
        sb.append("</trim>");
        return sb.toString();
    }

    private String getValueSql(TableInfo tableInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
        sb.append("<if test=\"data.").append(tableInfo.getKeyProperty())
                .append(" != null\">#{data.").append(tableInfo.getKeyProperty())
                .append("},</if>");
        tableInfo.getFieldList().forEach(field ->
                sb.append("<if test=\"data.").append(field.getProperty())
                        .append(" != null\">#{data.").append(field.getProperty())
                        .append("},</if>")
        );
        sb.append("</trim>");
        return sb.toString();
    }
}

将自定义的方法注入到 mp 的管理器中

将自定义的 batchInsert 及 batchInsertSelective,两个方法加入到 mp 的管理器。

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.fy.config.mybatis.plus.method.DemoBatchInsertMethod;
import com.fy.config.mybatis.plus.method.DemoBatchInsertSelectiveMethod;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * Description:自定义 sql 注入器
 *
 * @author fy
 * @version 1.0
 */
@Configuration
public class CustomizedSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        methodList.add(new DemoBatchInsertMethod());
        methodList.add(new DemoBatchInsertSelectiveMethod());
        return methodList;
    }
}

定义自己的顶层 mapper

自定一个 RootMapper,保留对 mp 的 BaseMapper 的传递,在该 mapper 中定义刚刚的两个方法。

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * Description:自定义顶层 Mapper
 *
 * @author fy
 * @version 1.0
 */
public interface RootMapper<E> extends BaseMapper<E> {

    /***
     * <p>
     * 自定义的批量新增方法
     * </p>
     * @author fy
     *
     * @param dataList 数据列表
     * @return int
     */
    int insertBatchDemo(@Param("dataList") List<E> dataList);

    /***
     * <p>
     * 自定义的批量新增方法
     * </p>
     * @author fy
     *
     * @param dataList 数据列表
     * @return int
     */
    int insertBatchSelectiveDemo(@Param("dataList") List<E> dataList);
}

继承自定义顶层 mapper

在需要批量操作的 mapper 上改成继承自定义的 RootMapper。

import com.fy.entity.User;
import com.fy.config.mybatis.plus.method.bean.RootMapper;

import java.util.List;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author fy
 */
public interface UserMapper extends RootMapper<User> {
}

使用

使用 spring 注入,然后调用即可

@Autowired
private UserMapper userMapper;

public void testMybatisPlusBatchInsertUser(int count) {
    long t1 = System.currentTimeMillis();
    userMapper.insertBatchDemo(getUserList(count));
    System.out.println("【mybatis-plus】插入条数:【" + count + "】耗时:【"
            + (System.currentTimeMillis() - t1) + "】");
}
结语

到此,使用 mybatis-plus 来 batch 写入数据的实现就介绍完了,后续继续其他方式的批量写入 …

如果您看到了这里,欢迎和我沟通交流!
             一个95后码农

个人博客:fy-blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值