MyBatis 中 OGNL 的使用:从入门到实战

1. 引言

OGNL(Object-Graph Navigation Language,对象图导航语言)是一种功能强大的表达式语言,最初用于 WebWork 框架,后来随着 Struts 2 的流行而被广泛熟知。在 MyBatis 中,OGNL 同样扮演着重要角色,它被用于动态 SQL 的表达式解析,让我们能够编写灵活、可复用的数据库查询语句。

本文将系统讲解 MyBatis 中 OGNL 的使用方法,从基础语法到高级技巧,帮助你在日常开发中熟练运用这一强大工具。

2. OGNL 基础语法

2.1 什么是 OGNL

OGNL 是一种表达式语言,它允许我们通过简单的表达式来访问和操作 Java 对象的属性、方法以及集合。在 MyBatis 中,OGNL 主要用于 <if><choose><where> 等动态 SQL 标签中的条件判断。

2.2 基本表达式

在 MyBatis 的 XML 映射文件中,OGNL 表达式通常写在 ${}#{} 中,但更常见的是直接写在动态 SQL 标签的属性值里:

xml 复制代码
<select id="findUsers" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null and name != ''">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

在上面的例子中,test 属性中的 name != null and name != '' 就是 OGNL 表达式。

2.3 常用运算符

OGNL 支持丰富的运算符,包括:

运算符类型 运算符 示例
关系运算 ==!=><>=<= age >= 18
逻辑运算 andornot name != null and age > 18
字符串运算 +(拼接) 'Hello' + name
三元运算 ? : sex == 1 ? '男' : '女'
成员运算 innot in id in (1, 2, 3)

3. MyBatis 中 OGNL 的典型应用场景

3.1 动态条件判断

这是 OGNL 最常用的场景,通过判断参数是否为空来动态拼接 SQL:

xml 复制代码
<select id="searchUsers" resultType="User">
    SELECT * FROM user
    <where>
        <if test="username != null and username.trim() != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
        <if test="startTime != null">
            AND create_time &gt;= #{startTime}
        </if>
    </where>
</select>

3.2 集合与数组判断

在处理批量操作或列表查询时,经常需要判断集合是否为空:

xml 复制代码
<select id="selectByIds" resultType="User">
    SELECT * FROM user
    <where>
        <if test="ids != null and ids.size() > 0">
            AND id IN
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
</select>

3.3 多条件选择

使用 <choose><when><otherwise> 实现类似 Java 中 switch-case 的逻辑:

xml 复制代码
<select id="queryUser" resultType="User">
    SELECT * FROM user
    <where>
        <choose>
            <when test="id != null">
                AND id = #{id}
            </when>
            <when test="username != null">
                AND username = #{username}
            </when>
            <otherwise>
                AND status = 1
            </otherwise>
        </choose>
    </where>
</select>

4. OGNL 高级用法

4.1 访问对象属性

OGNL 支持链式访问对象的嵌套属性:

xml 复制代码
<if test="user.address.city != null">
    AND city = #{user.address.city}
</if>

4.2 调用方法

可以在表达式中调用 Java 方法:

xml 复制代码
<if test="name != null and name.length() > 5">
    AND name = #{name}
</if>

4.3 使用静态方法

通过 @类名@方法名 调用静态方法:

xml 复制代码
<if test="@java.lang.String@isEmpty(name)">
    AND name IS NULL
</if>

4.4 访问静态常量

xml 复制代码
<if test="status == @com.example.constant.UserStatus@ACTIVE">
    AND status = #{status}
</if>

5. 常见问题与注意事项

5.1 特殊字符转义

在 XML 中,<>& 等字符需要转义:

原始字符 XML 转义
< &lt;
> &gt;
& &amp;

5.2 参数为 null 的判断

判断字符串是否为空时,建议同时判断 null 和空字符串:

xml 复制代码
<if test="name != null and name != ''">

5.3 避免 SQL 注入

使用 #{} 进行参数占位,不要使用 ${} 拼接用户输入:

xml 复制代码
<!-- 安全写法 -->
AND name = #{name}

<!-- 危险写法,存在 SQL 注入风险 -->
AND name = '${name}'

6. 实战案例:动态多条件查询

下面是一个综合运用 OGNL 的完整示例:

xml 复制代码
<select id="dynamicQuery" resultType="User" parameterType="map">
    SELECT * FROM user
    <where>
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="minAge != null">
            AND age &gt;= #{minAge}
        </if>
        <if test="maxAge != null">
            AND age &lt;= #{maxAge}
        </if>
        <if test="deptIds != null and deptIds.size() > 0">
            AND dept_id IN
            <foreach collection="deptIds" item="deptId" open="(" separator="," close=")">
                #{deptId}
            </foreach>
        </if>
        <if test="status != null">
            AND status = #{status}
        </if>
    </where>
    ORDER BY create_time DESC
</select>

对应的 Mapper 接口方法:

java 复制代码
public interface UserMapper {
    List<User> dynamicQuery(Map<String, Object> params);
}

调用示例:

java 复制代码
Map<String, Object> params = new HashMap<>();
params.put("name", "张");
params.put("minAge", 18);
params.put("maxAge", 30);
params.put("deptIds", Arrays.asList(1, 2, 3));
params.put("status", 1);

List<User> users = userMapper.dynamicQuery(params);

7. 总结

OGNL 是 MyBatis 动态 SQL 的核心支撑,掌握它能够让我们编写出更加灵活、强大的数据库操作语句。本文从基础语法、典型应用场景、高级用法到实战案例,系统介绍了 MyBatis 中 OGNL 的使用方法。

在实际开发中,建议遵循以下几点:

  • 优先使用 #{} 防止 SQL 注入
  • 注意 XML 特殊字符的转义
  • 合理使用 <where> 标签自动处理多余的 AND/OR
  • 对于复杂的查询条件,可以使用 <choose> 实现多分支逻辑

希望本文能帮助你更好地理解和使用 MyBatis 中的 OGNL,提升开发效率。

相关推荐
吴声子夜歌7 小时前
Java面试——算法
java·算法·面试
evans在进步7 小时前
LeetCode 64:最小路径和——Java 原地动态规划详解
java·leetcode·动态规划
凤山老林9 小时前
Spring Boot 3.x AOT 编译实战:从原理、踩坑到生产落地
java·spring boot·后端
博傅9 小时前
Spring 核心原理
java·后端·spring
yurenpai(27届找实习中)9 小时前
从零读懂 AI 智能客服(一):模块职责与 SSE 聊天链路(后端架构)
java·人工智能·架构·langchain4j
陈皮波比茶9 小时前
Swagger
java
小闫BI设源码10 小时前
Elasticsearch面试必看:如何让客户端精准选择节点高效执行请求?
java·elasticsearch·面试宝典·深入解析
摇滚侠10 小时前
《SpringBoot 3:入门与应用实战》第 5 章 使用 Spring Boot 阅读笔记 9
java·spring boot·笔记
进阶的小名10 小时前
Spring AI 2.0 探索:多 OpenAI-Compatible 模型接入,以及下一代 Session 记忆管理
java·人工智能·后端·gpt·spring·ai·chatgpt