logo

MyBatis模糊查询与IN条件操作全解析

作者:蛮不讲李2025.09.19 15:54浏览量:0

简介:本文详细解析MyBatis框架中模糊查询与IN条件查询的实现方法,结合XML映射文件与注解开发两种方式,提供完整代码示例与性能优化建议。

MyBatis模糊查询与IN条件操作全解析

一、模糊查询实现原理与核心方法

MyBatis的模糊查询主要通过SQL语句中的LIKE关键字实现,结合动态SQL功能可构建灵活的查询条件。在MyBatis中实现模糊查询有两种典型方式:

1.1 参数直接拼接方式

  1. <!-- UserMapper.xml -->
  2. <select id="selectByNameLike" resultType="User">
  3. SELECT * FROM user
  4. WHERE name LIKE CONCAT('%', #{keyword}, '%')
  5. </select>

这种方式通过MySQL的CONCAT函数直接拼接通配符,适用于简单场景。但存在SQL注入风险,需确保参数经过严格校验。

1.2 动态SQL绑定方式(推荐)

  1. <select id="selectByDynamicPattern" resultType="User">
  2. SELECT * FROM user
  3. WHERE name LIKE
  4. <bind name="pattern" value="'%' + keyword + '%'" />
  5. #{pattern}
  6. </select>

或使用<if>标签构建更复杂的条件:

  1. <select id="searchUsers" resultType="User">
  2. SELECT * FROM user
  3. WHERE 1=1
  4. <if test="name != null">
  5. AND name LIKE CONCAT('%', #{name}, '%')
  6. </if>
  7. <if test="email != null">
  8. AND email LIKE '%' || #{email} || '%'
  9. </if>
  10. </select>

关键点

  • 不同数据库的字符串拼接语法不同(MySQL用CONCAT,Oracle用||
  • 推荐使用<bind>标签预处理参数,提升可读性
  • 动态SQL可结合<where>标签自动处理AND/OR前缀

二、IN条件查询的深度实践

IN查询用于匹配多个离散值,在MyBatis中有三种实现方式:

2.1 静态IN列表

  1. <select id="selectByIds" resultType="User">
  2. SELECT * FROM user
  3. WHERE id IN (1, 2, 3, 5, 8)
  4. </select>

适用于固定值列表的场景,但实际开发中极少使用。

2.2 动态IN列表(数组/集合)

  1. // Mapper接口
  2. List<User> selectByIdList(@Param("ids") List<Long> ids);
  1. <select id="selectByIdList" resultType="User">
  2. SELECT * FROM user
  3. WHERE id IN
  4. <foreach item="id" collection="ids" open="(" separator="," close=")">
  5. #{id}
  6. </foreach>
  7. </select>

实现细节

  • collection属性对应方法参数名,若使用@Param注解则写注解值
  • item定义循环变量名,open/close定义括号,separator定义分隔符
  • 当集合为空时,默认会生成WHERE id IN ()导致语法错误,需配合<if>处理:
    1. <select id="safeSelectByIdList" resultType="User">
    2. SELECT * FROM user
    3. WHERE
    4. <if test="ids != null and ids.size() > 0">
    5. id IN
    6. <foreach item="id" collection="ids" open="(" separator="," close=")">
    7. #{id}
    8. </foreach>
    9. </if>
    10. <if test="ids == null or ids.size() == 0">
    11. 1=0 <!-- 返回空结果集 -->
    12. </if>
    13. </select>

2.3 注解方式实现IN查询

  1. @Select({
  2. "<script>",
  3. "SELECT * FROM user",
  4. "WHERE id IN",
  5. "<foreach item='id' collection='ids' open='(' separator=',' close=')'>",
  6. "#{id}",
  7. "</foreach>",
  8. "</script>"
  9. })
  10. List<User> selectByIdListAnnotated(@Param("ids") List<Long> ids);

注意事项

  • 必须使用<script>标签包裹动态SQL
  • 注解方式对复杂SQL可读性较差,建议简单场景使用

三、性能优化与最佳实践

3.1 模糊查询优化策略

  1. 避免前导通配符LIKE '%keyword'无法使用索引,应设计为LIKE 'keyword%'或全字段匹配
  2. 全文索引替代:对长文本字段,考虑使用MySQL的FULLTEXT索引或Elasticsearch
  3. 函数索引:MySQL 8.0+支持函数索引,可创建CREATE INDEX idx_name_fuzzy ON user((name))

3.2 IN查询优化方案

  1. 批量查询限制:建议单次IN列表不超过1000个值(不同数据库限制不同)
  2. 临时表方案:大数据量时改用临时表关联
    1. -- 创建临时表
    2. CREATE TEMPORARY TABLE temp_ids (id BIGINT);
    3. -- 批量插入
    4. INSERT INTO temp_ids VALUES (1),(2),(3);
    5. -- 关联查询
    6. SELECT u.* FROM user u JOIN temp_ids t ON u.id = t.id;
  3. 分页处理:结合ROW_NUMBER()LIMIT分批处理

3.3 动态SQL编写规范

  1. XML格式化:使用4空格缩进,保持结构清晰
  2. SQL注入防护
    • 避免直接拼接SQL片段
    • 使用#{}而非${}处理参数
  3. 日志调试:开启MyBatis日志查看最终执行的SQL
    1. # application.properties
    2. logging.level.org.mybatis=DEBUG

四、典型应用场景案例

4.1 多条件组合查询

  1. <select id="complexSearch" resultType="User">
  2. SELECT * FROM user
  3. <where>
  4. <if test="name != null">
  5. AND name LIKE CONCAT('%', #{name}, '%')
  6. </if>
  7. <if test="statusList != null and statusList.size() > 0">
  8. AND status IN
  9. <foreach item="status" collection="statusList" open="(" separator="," close=")">
  10. #{status}
  11. </foreach>
  12. </if>
  13. <if test="minAge != null">
  14. AND age >= #{minAge}
  15. </if>
  16. </where>
  17. ORDER BY create_time DESC
  18. </select>

4.2 批量操作与事务控制

  1. @Transactional
  2. public void batchUpdateStatus(List<Long> ids, Integer newStatus) {
  3. // 先查询存在性(可选)
  4. List<User> users = userMapper.selectByIdList(ids);
  5. if(users.size() != ids.size()) {
  6. throw new RuntimeException("部分ID不存在");
  7. }
  8. // 批量更新
  9. userMapper.batchUpdateStatus(
  10. ids,
  11. newStatus,
  12. new Date() // 更新时间
  13. );
  14. }
  1. <update id="batchUpdateStatus">
  2. UPDATE user
  3. SET status = #{newStatus},
  4. update_time = #{updateTime}
  5. WHERE id IN
  6. <foreach item="id" collection="ids" open="(" separator="," close=")">
  7. #{id}
  8. </foreach>
  9. </update>

五、常见问题解决方案

5.1 模糊查询返回空结果

原因分析

  1. 参数未正确传递
  2. 数据库字符集不匹配(如UTF-8 vs Latin1)
  3. 大小写敏感问题

解决方案

  1. <!-- 强制转换为小写比较 -->
  2. <select id="caseInsensitiveSearch" resultType="User">
  3. SELECT * FROM user
  4. WHERE LOWER(name) LIKE CONCAT('%', LOWER(#{keyword}), '%')
  5. </select>

5.2 IN查询参数过多

错误表现

  1. ORA-01795: maximum number of expressions in a list is 1000

解决方案

  1. 分批查询:
    1. public List<User> selectInBatches(List<Long> allIds, int batchSize) {
    2. List<User> result = new ArrayList<>();
    3. for(int i=0; i<allIds.size(); i+=batchSize) {
    4. List<Long> batch = allIds.subList(i, Math.min(i+batchSize, allIds.size()));
    5. result.addAll(userMapper.selectByIdList(batch));
    6. }
    7. return result;
    8. }
  2. 使用JOIN替代IN

六、进阶技巧:MyBatis-Plus集成

对于使用MyBatis-Plus的项目,可简化操作:

  1. // 模糊查询
  2. LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
  3. wrapper.like(User::getName, "张")
  4. .in(User::getStatus, Arrays.asList(1, 2, 3));
  5. List<User> users = userMapper.selectList(wrapper);
  6. // 批量操作
  7. userMapper.update(
  8. null,
  9. new LambdaUpdateWrapper<User>()
  10. .set(User::getStatus, 2)
  11. .in(User::getId, Arrays.asList(1L, 2L, 3L))
  12. );

总结:本文系统阐述了MyBatis中模糊查询与IN条件查询的实现方法,从基础语法到性能优化提供了完整解决方案。实际开发中,应结合业务场景选择合适方案,特别注意SQL注入防护和大数据量处理。通过合理使用动态SQL和数据库特性,可显著提升查询效率与系统稳定性。

相关文章推荐

发表评论