前言
开发中经常碰到的需要插入很多数据到数据库中的情况,如果采用循环单个插入的方式的话,整体看起来会比较简单,但是会造成频繁的数据库连接,影响数据库的处理效率和性能,这个时候,采用单次批量插入的方式就会更加高效,下面我们就来看一下采用mybatis如果批量的来插入数据到mysql数据库中。
处理实例
准备工作
创建mysql数据库表
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`age` bigint(20) NOT NULL COMMENT '用户年龄',
`create_user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '创建用户ID',
`is_delete` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除:0、否;1、是',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4;
创建数据库表对应实体类
@Data
public class User {
private Long id;
private Long age;
private Long createUserId;
private Integer isDelete;
private Date createTime;
private Date updateTime;
}
mybatis中的<foreach>标签介绍
<foreach>标签主要是对集合数据进行遍历处理的一个常用标签,该标签有如下的六个属性:item,index,collection,open,separator,close
- item:item属性是给遍历的每一个集合元素起一个别名,通过这个别名来进行每个集合元素的处理
- index:index属性是要遍历的List或Array的循环下标,主要用来定位当前处理元素
- collection:collection属性主要是用来表示需要循环处理的对象, collection可以是列表,也可以是数组,不同的数据结构collection设置的值是不同的
- open:整个循环的开始的字符,一般大部分是左括号"(", 非必选
- close:整个循环的结束的字符,一般大部分是右括号")", 非必选
- separator:元素之间的分隔符
采用<foreach>标签和@Insert注解的方式
- 批量插入的List没有通过@Param注解设定特定的key或者通过Map中一个key来传入该List对象,直接传入该对象List的这种情况,<foreach>标签中的collection直接为list
@Insert({"<script>",
"insert into user ( age, create_user_id )",
"values",
"<foreach collection='list' item='item' index='index' separator=',' > ( #{item.userId}, #{item.createUserId} ) </foreach>",
"</script>"})
int batchInsert(List<User> userList);
- 批量插入的List通过@Param注解为该参数设定了特定的key或者通过Map中的一个key来传入该List对象,例如下图中的通过@Param注解设定了参数的key为userList,则<foreach>标签中的collection直接为该key是 userList
@Insert({"<script>",
"insert into user ( age, create_user_id )",
"values",
"<foreach collection='userList' item='item' index='index' separator=',' > ( #{item.age}, #{item.createUserId} ) </foreach>",
"</script>"})
int batchInsertTwo(@Param("userList") List<User> userList);
- 如果批量插入的是一个对象数组的话,那么<foreach>标签中的collection对应的值应该是array,如下所示
@Insert({"<script>",
"insert into user ( age, create_user_id )",
"values",
"<foreach collection='array' item='item' index='index' separator=',' > ( #{item.age}, #{item.createUserId} ) </foreach>",
"</script>"})
int batchInsertThree(User[] userArray);
采用<foreach>标签和Xml文件的方式
- 采用直接传入单个List的方式对应的方法和xml配置
void batchInsert(List<User> userList);
<insert id="batchInsert" parameterType="java.util.List">
insert into user ( age, create_user_id )
values
<foreach item="item" collection="list" separator="," index="index">
( #{item.age}, #{item.createUserId} )
</foreach>
</insert>
- 采用Map的方式传入参数的
//param参数中的其中一个key为userList,对应的value为List<user>
void batchInsertTwo(Map param);
<insert id="batchInsertTwo">
insert into user ( age, create_user_id )
values
<foreach item="item" collection="userList" separator="," index="index">
( #{item.age}, #{item.createUserId} )
</foreach>
</insert>
- 采用数组的方式传入对象参数
//param参数中的其中一个key为userList,对应的value为List<user>
void batchInsertThree(User[] userArray);
<insert id="batchInsertThree">
insert into user ( age, create_user_id )
values
<foreach item="item" collection="array" separator="," index="index">
( #{item.age}, #{item.createUserId} )
</foreach>
</insert>
采用sqlSessionTemplate的方式
这种方式我们一般用的比较少,该方式主要使用的是SqlSessionTemplate的批量提交的模式来实现的,整体处理效率比直接通过for循环单个插入的方式要高一些,但是要比采用<foreach>标签的方式要低一些,实现代码如下:
@Autowired
SqlSessionTemplate sqlSessionTemplate;
public void userBatchInsert(Long userId, List<Long> userIdList) {
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);//跟上述sql区别
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user;
for (Long u : userIdList) {
user = new User();
user.setAge(10);
user.setCreateUserId(u);
userMapper.insert(user);
}
sqlSession.commit();
}
该方法对接的sql文件为:
@Insert({"insert into user set age = #{age}, create_user_id = #{createUserId} "})
int insert(User user);
总结
通过上面的介绍,我们应该已经了解了这几种常用的通过mybatis来进行批量插入到mysql数据的正确的操作方式,通过这样的方式可以极大的提高我们的整体的存储效率,实现更快的数据库插入,个人拙见,如果存在什么问题,希望大家可以提出来,我们一起来探讨,一起来进步,谢谢