说明:遇到一次需要批量修改对象的场景。传递一个对象集合,需要根据对象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 {@Autowiredprivate 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_usersetusername = 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>endwhere<foreach collection="users" item="user" separator="or">id = #{user.id}</foreach></update>
看着有些复杂,拼接后的SQL如下:
update tb_usersetusername = casewhen id = '1' then 'zhangsan_fix'when id = '2' then 'lisi_fix'end,password = casewhen id = '1' then passwordwhen id = '2' then '654321_fix'endwhere id = '1'or id = '2';
这种方式不需要加额外的配置,执行测试;
查看数据库,没得问题,批量修改完成了;
总结
本文介绍了Mybatis框架下,批量更新对象的两种方法:
-
方法一:将多条更新语句合成一条执行,需要在数据库链接后面增加配置,不能体现正常的修改记录条数,有SQL注入的风险;
-
方法二:使用case then 关键字实现,SQL复杂,行数多,降低了可阅读性;