重要提醒:使用
@Param
注解時,務必導入正確的包!
import org.apache.ibatis.annotations.Param;
很多開發者容易錯誤導入Spring的@Param
,導致參數綁定失敗!
一、為什么需要傳遞List參數?
最常見的場景是動態構建IN查詢:
SELECT * FROM users WHERE id IN (1, 2, 3, 4)
當我們需要根據前端傳入的多個值查詢時,就需要將List集合作為參數傳遞給Mapper。
二、基礎版:MyBatis原生List傳參
1. Mapper接口定義(注意@Param導入)
// !!!必須導入MyBatis的@Param包!!!
import org.apache.ibatis.annotations.Param;public interface UserMapper {// 使用@Param注解指定參數名List<User> selectByIds(@Param("idList") List<Long> idList);
}
2. XML映射文件實現
<select id="selectByIds" resultType="User">SELECT * FROM usersWHERE id IN<foreach collection="idList" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>
核心標簽解析:
屬性 | 說明 | 示例值 |
---|---|---|
collection | 傳入的集合參數名 | idList |
item | 循環中當前元素的別名 | id |
open | 循環開始前的字符串 | ( |
separator | 元素間的分隔符 | , |
close | 循環結束后的字符串 | ) |
3. 實際生成的SQL
當傳入List<Long> ids = Arrays.asList(1L, 2L, 3L)
時:
SELECT * FROM users WHERE id IN (1, 2, 3)
三、避坑重點:@Param的正確使用
常見錯誤1:導入錯誤包
// ? 錯誤:導入了Spring的Param包
import org.springframework.data.repository.query.Param;// ? 正確:必須使用MyBatis的Param包
import org.apache.ibatis.annotations.Param;
常見錯誤2:忘記添加@Param注解
// ? 錯誤:缺少@Param注解會導致XML中無法識別參數
List<User> selectByIds(List<Long> idList);// ? 正確:必須添加@Param注解
List<User> selectByIds(@Param("idList") List<Long> idList);
四、MyBatis Plus的優雅實現
1. 使用QueryWrapper(無需XML)
public List<User> getUsersByIds(List<Long> ids) {return userMapper.selectList(new QueryWrapper<User>().in("id", ids));
}
2. Lambda表達式寫法(推薦)
public List<User> getUsersByIds(List<Long> ids) {return userMapper.selectList(Wrappers.<User>lambdaQuery().in(User::getId, ids));
}
注意:MyBatis Plus的Wrapper方式不需要@Param注解
五、擴展應用場景
場景1:List處理
// Mapper
List<User> selectByNames(@Param("nameList") List<String> nameList);// XML
<foreach collection="nameList" item="name" open="(" separator="," close=")">#{name}
</foreach>
場景2:List<實體對象>
// Mapper
List<User> selectByConditions(@Param("userList") List<User> userList);// XML
<foreach collection="userList" item="user" separator=" OR ">(name = #{user.name} AND age > #{user.age})
</foreach>
場景3:多List參數
// Mapper
List<User> searchUsers(@Param("ids") List<Long> ids, @Param("names") List<String> names);// XML
<where><if test="ids != null and !ids.isEmpty()">id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach></if><if test="names != null and !names.isEmpty()">AND name IN<foreach collection="names" item="name" open="(" separator="," close=")">#{name}</foreach></if>
</where>
六、特殊類型處理技巧
1. 枚舉類型處理
// Mapper
List<User> selectByStatus(@Param("statusList") List<UserStatus> statusList);// XML
<foreach collection="statusList" item="status" open="(" separator="," close=")">#{status, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
</foreach>
2. 日期范圍查詢
// Mapper
List<User> selectByDates(@Param("dateList") List<Date> dates);// XML
<foreach collection="dateList" item="date" separator=" OR ">create_time BETWEEN #{date} AND DATE_ADD(#{date}, INTERVAL 1 DAY)
</foreach>
七、性能優化與避坑指南
1. 空集合安全處理
<select id="safeSelect">SELECT * FROM users<where><if test="idList != null and !idList.isEmpty()">id IN<foreach collection="idList" ... /></if></where>
</select>
2. 大數據量分批查詢
// 每500條執行一次查詢
public List<User> batchSelect(List<Long> allIds) {List<User> result = new ArrayList<>();int batchSize = 500;for (int i = 0; i < allIds.size(); i += batchSize) {List<Long> batchIds = allIds.subList(i, Math.min(i + batchSize, allIds.size()));result.addAll(userMapper.selectByIds(batchIds));}return result;
}
3. SQL注入防護
<!-- 安全寫法:使用#{}預編譯 -->
<foreach collection="names" item="name">#{name} <!-- 安全 -->
</foreach><!-- 危險寫法:${}直接拼接 -->
<foreach collection="names" item="name">'${name}' <!-- 存在SQL注入風險! -->
</foreach>
八、完整可運行示例
Controller
@RestController
@RequestMapping("/users")
public class UserController {@PostMapping("/by-ids")public List<User> getUsersByIds(@RequestBody List<Long> ids) {return userService.getUsersByIds(ids);}
}
Service
@Service
@RequiredArgsConstructor
public class UserService {private final UserMapper userMapper;public List<User> getUsersByIds(List<Long> ids) {if (ids == null || ids.isEmpty()) {return Collections.emptyList();}// 超過1000條自動分批return ids.size() > 1000 ? batchSelect(ids) : userMapper.selectByIds(ids);}
}
Mapper XML
<mapper namespace="com.example.mapper.UserMapper"><select id="selectByIds" resultType="User">SELECT id, name, email FROM users<where><if test="idList != null and !idList.isEmpty()">id IN<foreach collection="idList" item="id" open="(" separator="," close=")">#{id}</foreach></if></where></select>
</mapper>
總結:核心要點回顧
-
必須使用正確的@Param包
import org.apache.ibatis.annotations.Param;
-
XML循環核心語法
<foreach collection="參數名" item="元素名" open="開始符" separator="分隔符" close="結束符">#{元素名} </foreach>
-
最佳實踐選擇
- 簡單查詢:MyBatis Plus Wrapper
- 復雜SQL:MyBatis XML + foreach
- 超大數據:分批查詢
-
安全防護
- 始終使用
#{}
防止SQL注入 - 空集合檢查避免全表掃描
- 始終使用
-
特殊類型處理
- 枚舉:添加typeHandler
- 日期:指定jdbcType=TIMESTAMP
最后提醒: 當遇到參數綁定問題時,首先檢查@Param導入的包是否正確,這是最常見的錯誤根源!