Mybatis批量更新对象数据的两种实现方式
作者:何中应
这篇文章主要介绍了Mybatis批量更新对象数据的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
说明:
遇到一次需要批量修改对象的场景。
传递一个对象集合,需要根据对象ID批量修改数据库数据,使用的是MyBatis框架。查了一些资料,总结出两种实现方式。
创建Demo
首先,创建一个简单的Demo;
(User,用户对象)
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private String id;
private String username;
private String password;
}(UserController,用户控制器)
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
/**
* 根据ID查询用户
* @param id
* @return
*/
@GetMapping("/getUser/{id}")
public String getUser(@PathVariable("id") String id){
return userMapper.getUser(id).toString();
}
}(UserMapper,用户数据访问接口)
import com.hezy.pojo.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
User getUser(String id);
}数据库数据,tb_user表

项目启动,测试一下接口,没得问题;

批量更新
创建一个新的接口,用于触发批量更新对象的代码,内容是传递一个List集合对象给Mapper处理;
@GetMapping("/updateUser")
public void updateUser(){
ArrayList<User> users = new ArrayList<>();
User user1 = new User();
user1.setId("1");
user1.setUsername("zhangsan_fix");
User user2 = new User();
user2.setId("2");
user2.setUsername("lisi_fix");
user2.setPassword("654321_fix");
users.add(user1);
users.add(user2);
userMapper.updateUser(users);
}接下来,重点是Mapper.xml中的Statement要怎么写,继续往下看
方式一
首先,我们可以使用动态SQL,如下:
<update id="updateUser">
<foreach collection="users" item="user" separator=";">
update tb_user
<set>
<if test="user.username != null and user.username != ''">
username = #{user.username},
</if>
<if test="user.password != null and user.password != ''">
password = #{user.password}
</if>
</set>
where id = #{user.id}
</foreach>
</update>我们把拼接后的SQL打印出来,会发现一个问题。SQL中,分号(;)表示一条语句的结束,使用上面的方式拼接出来的方式,是多条SQL。

因此产生了一个问题,Mybatis中一个Statement标签中可以有多条SQL吗?
答案是默认不可以,所以上面的代码报错了。
需要在数据库连接后面加上&allowMultiQueries=true配置,如下:

再次执行,修改成功了,这是第一种方式;


查看日志发现,Updates:1,就是说如果需要返回更新的记录条数,那么这种方式返回的更新条数会是1,不能体现出数据库真实发生变化的记录条数;
另外,将多条SQL合成一条执行,有SQL注入的风险
方式二
第二种方式是用一条SQL的方式来实现,如下:
<update id="updateUser">
update tb_user
set
username = case
<foreach collection="users" item="user">
when id = #{user.id}
<choose>
<when test="user.username != null and user.username != ''">then #{user.username}</when>
<otherwise>then username</otherwise>
</choose>
</foreach>
end,
password = case
<foreach collection="users" item="user">
when id = #{user.id}
<choose>
<when test="user.password != null and user.password != ''">then #{user.password}</when>
<otherwise>then password</otherwise>
</choose>
</foreach>
end
where
<foreach collection="users" item="user" separator="or">
id = #{user.id}
</foreach>
</update>看着有些复杂,拼接后的SQL如下:
update tb_user set username = case when id = '1' then 'zhangsan_fix' when id = '2' then 'lisi_fix' end, password = case when id = '1' then password when id = '2' then '654321_fix' end where id = '1' or id = '2';
这种方式不需要加额外的配置,执行测试;

查看数据库,没得问题,批量修改完成了;

总结
本文介绍了Mybatis框架下,批量更新对象的两种方法:
- 方法一:将多条更新语句合成一条执行,需要在数据库链接后面增加配置,不能体现真实修改的记录条数,有SQL注入的风险;
- 方法二:使用case then 关键字实现,SQL复杂,行数多,降低了可阅读性;
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
