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。
文章介绍了在Mybatis-Plus中优化单表和多表批量插入的方法,包括使用自定义SQL和设置@Options注解来确保主键生成。作者分享了手动解决主键问题的两种方式:注解方式和XML配置。
384

被折叠的 条评论
为什么被折叠?



