Java MyBatis条件案例如何编写

wen java案例 29

Java MyBatis条件查询案例编写指南:从入门到高级实战

目录导读

  1. 引言:为什么需要掌握MyBatis条件查询?
  2. MyBatis基础回顾:配置与Mapper映射
  3. 简单条件查询案例:单参数与多参数
  4. 动态SQL条件拼接:if、where、set、trim标签详解
  5. 复杂条件组合:choose、when、otherwise多分支逻辑
  6. 关联查询与条件过滤:一对一、一对多场景
  7. 高级技巧:分页条件查询与批量操作
  8. 常见问题与问答集锦
  9. 总结与最佳实践

引言:为什么需要掌握MyBatis条件查询?

在实际Java企业级开发中,MyBatis作为最流行的ORM框架之一,其核心优势在于灵活的条件查询能力,据统计,超过70%的数据库操作涉及动态条件拼接,无论是简单的用户登录验证,还是复杂的报表筛选,正确编写条件案例直接决定了系统的查询效率与代码可维护性,本文将通过大量实战案例,系统讲解MyBatis条件查询的编写方法,帮助开发者避开常见陷阱。

Java MyBatis条件案例如何编写


MyBatis基础回顾:配置与Mapper映射

在编写条件查询前,确保项目已正确配置MyBatis核心组件:

XML映射文件结构

<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectByConditions" resultType="User">
        <!-- 具体SQL语句 -->
    </select>
</mapper>

关键点

  • resultType用于简单查询,resultMap用于复杂映射。
  • 参数传递支持 #{param}(预编译占位符)和 ${param}(字符串拼接,需防注入)。

简单条件查询案例:单参数与多参数

案例1:单参数条件

// 接口方法
User selectById(@Param("id") Long id);
// XML
<select id="selectById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>

注意:即使只有一个参数,也建议使用@Param注解明确参数名。

案例2:多参数条件

List<User> selectByNameAndAge(@Param("name") String name, 
                               @Param("age") Integer age);
<select id="selectByNameAndAge" resultType="User">
    SELECT * FROM user 
    WHERE name = #{name} AND age = #{age}
</select>

问答
:如果参数为null,直接使用WHERE name = #{name}会报错吗?
:不会报错,但查询结果不包含该条件,若需忽略null条件,需使用动态SQL。


动态SQL条件拼接:核心标签实战

1 <if>标签:根据条件动态包含片段

<select id="searchUsers" resultType="User">
    SELECT * FROM user WHERE 1=1
    <if test="name != null and name != ''">
        AND name LIKE CONCAT('%', #{name}, '%')
    </if>
    <if test="age != null">
        AND age = #{age}
    </if>
</select>

注意:为什么要加WHERE 1=1?避免所有条件为假时SQL变为WHERE AND...

2 <where>标签:智能处理WHERE子句

<select id="searchUsers" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

优势:自动去除多余AND/OR,且无1=1冗余。

3 <set>标签:动态更新字段

<update id="updateUser">
    UPDATE user
    <set>
        <if test="name != null">name = #{name},</if>
        <if test="age != null">age = #{age},</if>
    </set>
    WHERE id = #{id}
</update>

原理:自动删除末尾逗号,避免SQL语法错误。

4 <trim>标签:自定义前缀/后缀

<select id="selectWithTrim" resultType="User">
    SELECT * FROM user
    <trim prefix="WHERE" prefixOverrides="AND |OR ">
        <if test="name != null">AND name = #{name}</if>
        <if test="age != null">OR age = #{age}</if>
    </trim>
</select>

参数说明prefix添加前缀,prefixOverrides截断多余连接词。


复杂条件组合:多分支逻辑

1 <choose><when><otherwise>:多路选择

<select id="selectByChoose" resultType="User">
    SELECT * FROM user
    <where>
        <choose>
            <when test="name != null">
                AND name = #{name}
            </when>
            <when test="age != null">
                AND age = #{age}
            </when>
            <otherwise>
                AND status = 'ACTIVE'
            </otherwise>
        </choose>
    </where>
</select>

场景:实现“按名称查询,若名称无则按年龄,若都无则查活跃用户”。


关联查询与条件过滤

1 一对一关联条件

<resultMap id="UserWithRoleMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="role" javaType="Role">
        <id property="roleId" column="role_id"/>
        <result property="roleName" column="role_name"/>
    </association>
</resultMap>
<select id="selectUserWithRole" resultMap="UserWithRoleMap">
    SELECT u.*, r.role_name
    FROM user u
    LEFT JOIN role r ON u.role_id = r.role_id
    <where>
        <if test="roleName != null">
            r.role_name = #{roleName}
        </if>
    </where>
</select>

2 一对多集合条件

<resultMap id="UserWithOrdersMap" type="User">
    <id property="id" column="id"/>
    <collection property="orders" ofType="Order"
                select="selectOrdersByUserId"
                column="id">
    </collection>
</resultMap>
<select id="selectOrdersByUserId" resultType="Order">
    SELECT * FROM orders WHERE user_id = #{userId}
    <if test="orderStatus != null">
        AND status = #{orderStatus}
    </if>
</select>

注意:子查询中的条件参数需通过column传值。


高级技巧:分页条件查询与批量操作

1 分页+动态条件(使用PageHelper插件)

// Service层
PageHelper.startPage(pageNum, pageSize);
List<User> list = userMapper.selectByPage(name, age);
PageInfo<User> pageInfo = new PageInfo<>(list);
// XML无需改动,只保留动态条件
<select id="selectByPage" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null">AND name = #{name}</if>
        <if test="age != null">AND age = #{age}</if>
    </where>
</select>

2 批量条件查询:<foreach>
<select id="selectByIds" resultType="User">
    SELECT * FROM user
    WHERE id IN
    <foreach collection="idList" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

参数collection必须对应接口的@Param("idList")

问答
<foreach>处理大量数据时性能如何?
:一般建议列表长度不超过1000,否则考虑分批次查询或临时表。


常见问题与问答集锦

Q1:动态条件中如何处理IN子查询的null判断?

<if test="idList != null and idList.size() > 0">
    AND id IN 
    <foreach collection="idList" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</if>

Q2:条件查询时如何避免SQL注入?

:始终使用占位符,禁止拼接字符串,仅用于传递表名/列名等非查询参数。

Q3:多条件查询时性能优化建议?

  • 对经常作为条件的字段建立索引(如nameage)。
  • 避免在<if>中使用LIKE '%keyword%',改用全文索引或分词。
  • 使用<where>替代1=1,提升可读性。

Q4:MyBatis的@Param注解何时必须用?

:当方法有多个参数且未使用@Param时,MyBatis无法自动绑定参数名,需通过param1param2访问,建议始终显式注解。


总结与最佳实践

核心要点

  1. 明确需求:区分静态条件与动态条件,避免过度使用<if>
  2. 善用:替代手动拼接1=1,提高代码简洁性。
  3. 警惕空指针:字符串检查用!= null and != '',集合用size() > 0
  4. 合理使用:处理复杂前缀后缀需求。
  5. 关联查询分离:优先使用懒加载(如@One@Many)减少冗余查询。

实战建议

  • 为每个Mapper增加单元测试,覆盖“所有条件都传”和“没有条件”两种极端场景。
  • 日志开启MyBatis SQL打印(mybatis.configuration.log-impl=STDOUT_LOGGING)方便调试。
  • 条件查询的DTO(数据传输对象)应设计为Optional字段,避免基础类型默认值干扰。

通过本文的系统学习,您应能独立编写从简单到复杂的MyBatis条件查询案例。动态SQL的核心是平衡灵活性与可维护性——在业务逻辑不断变化时,MyBatis的条件机制是您最可靠的伙伴。

抱歉,评论功能暂时关闭!