mybatis-plus使用实体,实现单表、多表(包含外键关系)批量插入数据

文章介绍了在Mybatis-Plus中优化单表和多表批量插入的方法,包括使用自定义SQL和设置@Options注解来确保主键生成。作者分享了手动解决主键问题的两种方式:注解方式和XML配置。
摘要由CSDN通过智能技术生成

mybatis-plus单表批量插入数据

在日常开发业务中,使用mybatis-plus做大数据量批量插入动作时,会发现插入效率比较缓慢。
假如我们有一张user表,如下:

@Getter
@Setter
@TableName("user")
public class User implements Serializable {
	@TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 名称
     */
    private String name;
  	/**
     * 年龄
     */
    private integer age;
    ...

}

我们在mybatis-plus中,使用Service 自带的 userService.saveBatch(),其本质上,还是用for循环执行insert动作。如下,是mybatis-plus saveBatch的源码:

在这里插入图片描述
最终执行的sql如下:

insert into user(name,age) values ("张三",10);
insert into user(name,age) values ("李四",11);
insert into user(name,age) values ("王五",11);

然而,执行批量插入的的时候,期待的sql应该是这样的:

insert into user(name,age) values ("张三",10),("李四",11),("王五",11);

所以,这个时候mybatis-plus并不能满足我们的要求。

网上,关于mybatis的批量插入,可以使用自定义sql注入器。

public class InsertBatchSqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new InsertBatchSomeColumn()); //添加InsertBatchSomeColumn方法
        return methodList;
    }
}

然后,在MybatisPlusConfig 中实例InsertBatchSqlInjector :

@Component
public class MybatisPlusConfig {
    @Bean
    public InsertBatchSqlInjector easySqlInjector () {
        return new InsertBatchSqlInjector();
    }
}

在mapper接口中定义insertBatchSomeColumn方法,

@Mapper
public interface UserMapper extends BaseMapper<User> {
    void insertBatchSomeColumn(@Param("list") List<User> userList);
}

以上方案,我尝试过,但是失败了,报错:Invalid bound statement 。我暂时没找到原因。
所以,我决定换一种简单明了的方式。
在mapper中,自定义一个sql语句,使用foreach循环实体参数的list:
一:UserMapper 接口使用@Insert注解自定义sql

@Mapper
public interface UserMapper extends BaseMapper<User> {

	@Insert({
            "<script>",
            "INSERT INTO user(name,age ) VALUES ",
            "<foreach collection='list' item='item' index='index' separator=','>",
                "(#{item.name}, #{item.age})",
            "</foreach>",
            "</script>"
    })
    void insertBatchSomeColumn(@Param("list") List<User> list);
}

二:在UserMapper.xml中自定义sql
UserMapper接口:

@Mapper
public interface UserMapper extends BaseMapper<User> {
    void insertBatchSomeColumn(@Param("list") List<User> list);
}

UserMapper.xml文件:

<insert id="insertBatchSomeColumn" parameterType="java.util.List">
    INSERT INTO user (name, age) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.name}, #{item.age})
    </foreach>
</insert>

接下来,service层做方法调用:
UserService接口

public interface UserService extends IService<User> {
	void insertBatch(List<User> userList);
}

UserServiceImpl 类

@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper , User> implements UserService {
	@Resource
    private UserMapper userMapper;
	
    @Override
    public void insertBatch(List<User> userList) {
    	userMapper.insertBatchSomeColumn(userList);
    }
}

以上,基本能完成mybatis-plus的单表批量插入工作。

mybatis-plus多表批量插入数据

当我们在执行完userMapper.insertBatchSomeColumn(userList)方法之后,我们需要把user的主键id,保存在另一张表user_log的一个外键字段。我们会发现userList中的user对象中id字段为空。

@Getter
@Setter
@TableName("user_log")
public class UserLog implements Serializable {
	@TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 用户id
     */
    private Long userId;
    /**
     * 操作类型
     * 1:注册,2:登录,3:。。。
     */
    private Integer operateType;
    ...

}
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper , User> implements UserService {
	@Resource
    private UserMapper userMapper;
    @Resource
    private UserLogMapper userLogMapper;
	
    @Override
    public void insertBatch(EList<User> userList) {
        userMapper.insertBatchSomeColumn(userList);
        List<UserLog> logList = new ArrayList<>();
        for (User user : userList) {
            Long userId = user.getId();
            //userId为空
            System.out.println(userId);
            UserLog userLog = new UserLog();
            userLog.setUserId(userId);
            userLog.setOperateType(1);
            ...
            logList.add(userLog); 
        }
        //userLogMapper参照userMapper
        userLogMapper.insertBatchSomeColumn(logList);
    }
}

最后查询数据库会发现,user_log中,user_id字段为空。
在mybatis中,单个实体的insert时,在save(user)之后,user.getId()时可用获取到当前操作的自动主键id的值,但是自己手写的批量插入,却获取不到,此时,我们需要修改一下自定义的sql,同样,两种方式:
一:UserMapper 接口使用@Options注解

@Mapper
public interface UserMapper extends BaseMapper<User> {
	@Options(useGeneratedKeys = true, keyProperty = "id",keyColumn = "id")
	@Insert({
            "<script>",
            "INSERT INTO user(name,age ) VALUES ",
            "<foreach collection='list' item='item' index='index' separator=','>",
                "(#{item.name}, #{item.age})",
            "</foreach>",
            "</script>"
    })
    void insertBatchSomeColumn(@Param("list") List<User> list);
}

二:UserMapper.xml文件

 <insert id="insertBatchSomeColumn" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="java.util.List">
        INSERT INTO user (name, age) VALUES
        <foreach collection="list" item="item" separator=",">
            (#{item.name}, #{item.age})
        </foreach>
 </insert>

至此,mybatis-plus的多表批量插入的基本功能完成。
注:本菜鸟使用的是注解方式,经过验证可以在user_log中查到user_id。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值