Mybatis批量操作
文章目录
- Mybatis批量操作
- 1 数据库结构
- 2 JDBC配置及Mapper映射配置
- 3 实体类
- 4 持久层类
- 5 映射文件
- 6 测试方法
- 7 总结
1 数据库结构
2 JDBC配置及Mapper映射配置
项目结构如下:
yml文件:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/example?allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
mybatis:
type-aliases-package: com.iotat.weather.pojo
mapper-locations: classpath:mapper/*.xml
注意:
url
需要添加allowMultiQueries=true
参数,允许批量操作,具体详情,参考这篇文章:
- Jdbc Url 设置allowMultiQueries为true和false时底层处理机制研究
- 我的MySQL版本是8,所以还需要加
serverTimezone=GMT%2B8
3 实体类
public class User {
private Integer id;
private String userName;
private String password;
//以下省略toString()方法和setter、getter方法
}
4 持久层类
@Mapper
@Repository
public interface UserMapper {
List<User> findAll();
void saveUser(List<User> users);
void updateUser(List<User> users);
}
5 映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jk.login.mapper.UserMapper">
<!--结果集映射-->
<resultMap id="userMap" type="User">
<result column="id" property="id"/>
<result column="u_name" property="userName"/>
<result column="u_psw" property="password"/>
</resultMap>
<select id="findAll" resultMap="userMap">
select * from tb_user
</select>
<insert id="saveUser" parameterType="java.util.List">
insert into tb_user(u_name,u_psw) values
<foreach collection="list" index="index" item="item" separator=",">
(#{item.userName},#{item.password})
</foreach>
</insert>
<update id="updateUser" parameterType="java.util.List">
<foreach collection="list" index="index" item="item" separator=";">
update tb_user set u_psw = #{item.password} where u_name = #{item.userName}
</foreach>
</update>
</mapper>
注意:
- 关于
foreach标签
的属性,可以参考以下博客:
- MyBatis:SQL语句中的foreach标签的详细介绍
- MyBatis动态sql之foreach标签
-
item
表示集合中迭代的对象 -
index
表示迭代到的位置 -
open
表示该语句以什么开始 -
separator
表示每次迭代之间的分隔符 -
close
表示以什么结束
foreach标签
的实质是拼接SQL
语句,我们需要重点关注的是collection
标签和separator
,前者表示需要迭代对象的类型,后者表示每次迭代之间的分割符号。- 在这里我的
insert标签
循环拼接的是values
后面的语句,最终的拼接结果如下:
insert into tb_user(u_name,u_psw) values
(userName1,password1),
(userName2,password2),
(userName3,password3),
...
如上所示,在insert标签
中循环拼接的结果是一条SQL
语句,所以用逗号作为分隔符,分隔每个value
值。
- 在这里我的
update标签
循环的是整条SQL
语句,最终的循环结果如下:
update tb_user set u_psw = password1 where u_name = userName1;
update tb_user set u_psw = password2 where u_name = userName2;
update tb_user set u_psw = password3 where u_name = userName3;
...
如上所示,在update标签
中循环拼接的结果是多条SQL语句
,所以用分号隔开,分隔每条SQL
语句。而且还需要在jdbc配置
的URL连接
处添加allowMultiQueries=true
参数,否则就算语法是正确的,程序也会报错,是一个小坑。
6 测试方法
@Autowired
UserMapper userMapper;
@Test
void testSave() {
List<User> list = new ArrayList<>();
User user1 = new User();
user1.setUserName("admin");
user1.setPassword("111");
User user2 = new User();
user2.setUserName("normal");
user2.setPassword("222");
User user3 = new User();
user3.setUserName("general");
user3.setPassword("333");
list.add(user1);
list.add(user2);
list.add(user3);
userMapper.saveUser(list);
}
可以看到,批量插入成功了,下面测试批量更新。
@Test
void testUpdate(){
List<User> list = userMapper.findAll();
List<User> newList = new ArrayList<>();
for (User u : list){
u.setPassword("111111");
newList.add(u);
}
userMapper.updateUser(newList);
}
上面代码是将所有账户的密码都设置成6个1,效果如下:
7 总结
- 采坑1:
url
连接处需要设置allowMultiQueries=true
,允许批量操作。 - 采坑2:
foreach
标签的separator
属性需根据实际的SQL
语句决定。 - 采坑3:不熟悉
SQL
语法,在写原生SQL
的时候先去数据库里测试语法是否正确。