一、引言

在 MyBatis 的 XML 映射文件里有时候需要引用的变量,在java里面定义的是枚举类型,我们需要正确使用

二、两种方式

(一)使用 @全限定类名@常量名 这种形式来引用枚举常量

合理运用枚举引用语法能够让你在 SQL 映射文件里方便地使用枚举类型。下面从基本引用、集合操作、自定义类型处理器等方面详细介绍 MyBatis 中的枚举引用语法
在 MyBatis 的 SQL 映射文件里,能够使用 @全限定类名@常量名 这种形式来引用枚举常量
假设存在如下枚举类:

package com.example.enums;

public enum Status {
    ACTIVE,
    INACTIVE
}
1. 在 MyBatis 的 XML 映射文件中,可按如下方式引用该枚举常量:
<select id="selectByStatus" resultType="YourResultType">
    SELECT * FROM your_table
    WHERE status = #{status}
</select>

在 Java 代码里调用该方法时:

import com.example.enums.Status;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

public class Main {
    public static void main(String[] args) {
        SqlSessionFactory sqlSessionFactory = ...; // 获取 SqlSessionFactory
        try (SqlSession session = sqlSessionFactory.openSession()) {
            session.selectList("selectByStatus", Status.ACTIVE);
        }
    }
}
2. 在条件判断中引用枚举

在 标签的条件判断里,可以使用枚举引用语法。
示例代码

<select id="selectByCondition" resultType="YourResultType">
    SELECT * FROM your_table
    <where>
        <if test="status != null and status == @com.example.enums.Status@ACTIVE">
            AND status = 'ACTIVE'
        </if>
    </where>
</select>
3. 在集合操作中引用枚举

要是参数是集合类型,可使用 contains 方法来判断集合是否包含某个枚举常量。
示例代码

<select id="selectByStatusList" resultType="YourResultType">
    SELECT * FROM your_table
    <where>
        <if test="statusList != null and statusList.contains(@com.example.enums.Status@ACTIVE)">
            AND status = 'ACTIVE'
        </if>
    </where>
</select>

在 Java 代码里调用该方法时:

import com.example.enums.Status;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        SqlSessionFactory sqlSessionFactory = ...; // 获取 SqlSessionFactory
        List<Status> statusList = Arrays.asList(Status.ACTIVE, Status.INACTIVE);
        try (SqlSession session = sqlSessionFactory.openSession()) {
            session.selectList("selectByStatusList", statusList);
        }
    }
}
4. 自定义类型处理器

MyBatis 默认会把枚举的名称(name() 方法返回值)当作字符串处理。若你想自定义枚举和数据库字段的映射关系,可使用自定义类型处理器。
示例代码

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedTypes(Status.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class StatusTypeHandler extends BaseTypeHandler<Status> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Status parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.name());
    }

    @Override
    public Status getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return value == null ? null : Status.valueOf(value);
    }

    @Override
    public Status getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        return value == null ? null : Status.valueOf(value);
    }

    @Override
    public Status getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return value == null ? null : Status.valueOf(value);
    }
}

在 MyBatis 的配置文件里注册该类型处理器:

<typeHandlers>
    <typeHandler handler="com.example.handlers.StatusTypeHandler"/>
</typeHandlers>

注意事项

  • 全限定类名要准确:在使用 @全限定类名@常量名 时,全限定类名必须准确无误,不然会引发类找不到的异常。
  • 类型处理器的注册:若使用自定义类型处理器,要确保在 MyBatis 配置文件中正确注册。
  • 空值处理:在进行条件判断时,要注意对空值进行处理,避免出现空指针异常。

(二)使用枚举的 name() 方法

1. 在条件判断中使用 name() 方法

在 标签的条件判断里,你可以使用枚举的 name() 方法来和字符串进行比较,以此决定是否添加某些 SQL 片段。
示例代码
假设存在如下枚举类:

package com.example.enums;

public enum OrderStatus {
    PENDING,
    PROCESSING,
    COMPLETED
}

在 MyBatis 的 XML 映射文件中可以这样使用:

<select id="selectOrdersByStatus" resultType="com.example.entity.Order">
    SELECT * FROM orders
    <where>
        <if test="orderStatus != null and orderStatus.name() == 'PROCESSING'">
            AND status = 'PROCESSING'
        </if>
    </where>
</select>
  • 在这个例子里,当传入的 orderStatus 枚举对象的名称是 PROCESSING 时,就会在 SQL 查询里添加 AND
    status = ‘PROCESSING’ 条件。
2. 在动态 SQL 拼接中使用 name() 方法

你还能在动态 SQL 拼接时使用 name() 方法,把枚举的名称作为 SQL 语句的一部分。
示例代码

<select id="selectOrdersByStatusWithDynamicSql" resultType="com.example.entity.Order">
    SELECT * FROM orders
    <where>
        <if test="orderStatus != null">
            AND status = #{orderStatus.name()}
        </if>
    </where>
</select>

这里直接将 orderStatus 枚举对象的名称作为参数传递给 SQL 查询。

注意事项

  • 空值检查:在使用 name() 方法之前,要确保枚举对象不为 null,不然会引发空指针异常。像上面的例子中,都添加了orderStatus != null 的检查。
  • 枚举名称一致性:要保证 SQL 语句里使用的字符串和枚举常量的名称一致,否则比较结果会出错。

(三)与直接引用枚举常量的对比

  • 使用 name() 方法的优势:

可读性好:对于不熟悉 MyBatis 枚举引用语法(@全限定类名@常量名)的开发者而言,name() 方法的比较方式更直观易懂。
可移植性强:这种方式不依赖于特定的类路径引用,在不同环境或框架中使用时,相对更通用。

  • 使用 name() 方法的劣势:

代码冗余:如果需要多次使用同一个枚举常量进行比较,每次都要写 name() 方法和对应的字符串,会使代码显得冗长。
硬编码风险:直接使用字符串进行比较,若枚举常量的名称发生变化,需要手动修改所有比较的字符串,容易出错。

三、总结

如果你是对单个枚举对象进行判断,使用 name() 方法 更合适;如果是对集合中的枚举元素进行判断,使用 引用枚举常量方法会更方便

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐