插件窝 干货文章 如何根据变量动态执行 MyBatis SQL 语句?

如何根据变量动态执行 MyBatis SQL 语句?

name age 使用 select 965    来源:    2025-03-31

动态执行 MyBatis SQL 语句的方法

在 MyBatis 中,有几种方式可以根据变量动态执行 SQL 语句:

1. 使用动态 SQL 标签

MyBatis 提供了一系列动态 SQL 标签:

<select id="findUsers" parameterType="map" resultType="User">
  SELECT * FROM users
  <where>
    <if test="name != null">
      AND name = #{name}
    </if>
    <if test="age != null">
      AND age = #{age}
    </if>
    <choose>
      <when test="orderBy == 'name'">
        ORDER BY name
      </when>
      <when test="orderBy == 'age'">
        ORDER BY age
      </when>
      <otherwise>
        ORDER BY id
      </otherwise>
    </choose>
  </where>
</select>

2. 使用 <script> 标签执行动态 SQL

可以在 Mapper 接口中使用 @Select 注解结合 <script> 标签:

@Select({"<script>",
         "SELECT * FROM users",
         "<where>",
         "  <if test='name != null'> AND name = #{name}</if>",
         "  <if test='age != null'> AND age = #{age}</if>",
         "</where>",
         "</script>"})
List<User> findUsers(Map<String, Object> params);

3. 使用 Provider 动态生成 SQL

创建 SQL 提供者类:

public class UserSqlProvider {
    public String findUsers(Map<String, Object> params) {
        return new SQL() {{
            SELECT("*");
            FROM("users");
            if (params.get("name") != null) {
                WHERE("name = #{name}");
            }
            if (params.get("age") != null) {
                WHERE("age = #{age}");
            }
        }}.toString();
    }
}

然后在 Mapper 接口中使用:

@SelectProvider(type = UserSqlProvider.class, method = "findUsers")
List<User> findUsers(Map<String, Object> params);

4. 使用 @Select 注解结合条件判断

@Select("SELECT * FROM users WHERE " +
        "#{name} IS NULL OR name = #{name} AND " +
        "#{age} IS NULL OR age = #{age}")
List<User> findUsers(@Param("name") String name, @Param("age") Integer age);

5. 使用 MyBatis-Plus 的条件构造器

如果你使用 MyBatis-Plus,可以使用其条件构造器:

public List<User> findUsers(String name, Integer age) {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    if (name != null) {
        queryWrapper.eq("name", name);
    }
    if (age != null) {
        queryWrapper.eq("age", age);
    }
    return userMapper.selectList(queryWrapper);
}

注意事项

  1. 动态 SQL 容易导致 SQL 注入风险,确保所有用户输入都经过验证和转义
  2. 复杂的动态 SQL 可能会影响性能,考虑使用缓存
  3. 对于特别复杂的查询,可以考虑使用存储过程

选择哪种方法取决于你的具体需求和项目架构。对于简单的条件查询,动态 SQL 标签通常是最方便的;对于复杂的逻辑,SQL 提供者可能更合适。