MyBatis-Plus 使用 Wrapper 自定义 SQL 查询

目录

[1. 注意事项](#1. 注意事项)

[2. 示例代码](#2. 示例代码)

[2.1 实体类](#2.1 实体类)

[2.2 Mapper 接口](#2.2 Mapper 接口)

[2.3 测试类](#2.3 测试类)

[3. 运行效果](#3. 运行效果)

[4. 总结](#4. 总结)


在实际项目中,虽然 MyBatis-Plus 提供了丰富的内置方法和 QueryWrapper 条件构造器,但有时我们需要 自定义 SQL 来实现更复杂的查询逻辑。

MyBatis-Plus 从 3.0.7 版本开始 支持 Wrapper 自定义 SQL ,结合 ${ew.customSqlSegment},可以在 XML 或注解中编写动态 SQL,灵活性更高。


1. 注意事项

在使用 Wrapper 自定义 SQL 时,需要注意以下几点:

  1. 版本要求

    MyBatis-Plus 版本必须 ≥ 3.0.7

    低版本不支持 customSqlSegment

  2. 参数命名

    Wrapper 参数必须命名为 ew

    或者用 @Param(Constants.WRAPPER) 明确指定。

  3. SQL 引用方式

    在 SQL 语句中,使用 ${ew.customSqlSegment} 引入 Wrapper 生成的 SQL 条件片段。

  4. 不支持基于 entity 的 where

    自定义 SQL 时,Wrapper 不会基于实体类自动生成 where 条件,需要自己写 SQL。


2. 示例代码

2.1 实体类

文件:User.java

java 复制代码
package com.example.pojo;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String username;
    private String info;
    private Integer balance;
}

2.2 Mapper 接口

文件:UserMapper.java

java 复制代码
package com.example.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper extends BaseMapper<User> {

    // 使用 Wrapper 自定义 SQL
    @Select("SELECT id, username, info, balance FROM user ${ew.customSqlSegment}")
    List<User> selectByCustomSql(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

2.3 测试类

文件:UserMapperTest.java

java 复制代码
package com.example;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testSelectByCustomSql() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .like("username", "o")   // 模糊匹配 username
                .ge("balance", 1000);    // balance >= 1000

        List<User> users = userMapper.selectByCustomSql(wrapper);
        users.forEach(System.out::println);
    }
}

3. 运行效果

生成的 SQL:

sql 复制代码
SELECT id, username, info, balance
FROM user
WHERE (username LIKE '%o%' AND balance >= 1000)

返回结果:

java 复制代码
User(id=1, username=Tom, info=喜欢运动, balance=2000)
User(id=3, username=Bob, info=游戏达人, balance=1500)

4. 总结

  • @Select("... ${ew.customSqlSegment}") 可以结合 Wrapper 动态拼接条件,避免大量 XML 配置。

  • 参数必须用 @Param(Constants.WRAPPER) 标记,或者命名为 ew

  • 灵活度比单纯 BaseMapper 的内置方法更高,适合需要部分自定义 SQL 的场景。

👉 建议在 复杂 SQL + 动态条件的场景下使用,简化 SQL 管理的同时又保留了 MyBatis-Plus 的便利性。