說明:遇到一次需要批量修改對象的場景。傳遞一個對象集合,需要根據對象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復雜,行數多,降低了可閱讀性;