• MybatisPlus 一些技巧


    查询简化

    SimpleQuery

    有工具类 com.baomidou.mybatisplus.extension.toolkit.SimpleQueryselectList 查询后的结果进行了封装,使其可以通过 Stream 流的方式进行处理,从而简化了 API 的调用。

    方法 list()

    支持对一个列表提取某个字段,并同时执行任意多个 Consumer。可以省去 for 循环或 stream().forEach()。

    // 假设有一个 User 实体类和对应的 BaseMapper
    List<Long> ids = SimpleQuery.list(
        Wrappers.lambdaQuery(User.class), // 使用 lambda 查询构建器
        User::getId, // 提取的字段,这里是 User 的 id
        System.out::println, // 第一个 peek 操作,打印每个用户
        user -> userNames.add(user.getName()) // 第二个 peek 操作,将每个用户的名字添加到 userNames 列表中
    );
    

    方法 keyMap()

    可以得到一个 key 是指定字段的值,value 是对应实体的 Map,方便用于需要根据某个字段查找对应实体的情况。参数也包含任意个 Consumer。

    // 假设有一个 User 实体类和对应的 BaseMapper
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户
    
    // 使用 keyMap 方法查询并封装结果
    Map<String, User> userMap = SimpleQuery.keyMap(
        queryWrapper, // 查询条件构造器
        User::getUsername, // 使用用户名作为键
        user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
    );
    
    // 遍历结果
    for (Map.Entry<String, User> entry : userMap.entrySet()) {
        System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
    }
    

    方法 map()

    可以得到一个 key 是指定字段的值,value 也是指定字段的值 Map。可以用于如字典的这种情况。

    // 假设有一个 User 实体类和对应的 BaseMapper
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户
    
    // 使用 map 方法查询并封装结果
    Map<String, Integer> userMap = SimpleQuery.map(
        queryWrapper, // 查询条件构造器
        User::getUsername, // 使用用户名作为键
        User::getAge, // 使用年龄作为值
        user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
    );
    
    // 遍历结果
    for (Map.Entry<String, Integer> entry : userMap.entrySet()) {
        System.out.println("Username: " + entry.getKey() + ", Age: " + entry.getValue());
    }
    

    方法 group()

    可以对查询结果按照实体的某个熟悉进行分类,得到一个 Map。也支持进行任意额外的副操作。并且对分组后的集合也支持下游收集器 Collector 进行进一步处理。

    // 假设有一个 User 实体类和对应的 BaseMapper
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户
    
    // 使用 group 方法查询并封装结果,按照用户名分组
    Map<String, List<User>> userGroup = SimpleQuery.group(
        queryWrapper, // 查询条件构造器
        User::getUsername, // 使用用户名作为分组键
        user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
    );
    
    // 遍历结果
    for (Map.Entry<String, List<User>> entry : userGroup.entrySet()) {
        System.out.println("Username: " + entry.getKey());
        for (User user : entry.getValue()) {
            System.out.println(" - User: " + user);
        }
    }
    

    查询条件 QueryWrapper

    inSql

    用于设置单个字段的 IN 条件,但与 in 方法不同的是,inSql 允许你直接使用 String 来传递要查询的范围。

    in 的方式:

    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.in(User::getAge, Arrays.asList(1, 2, 3));
    
    -- 生成的 SQL
    SELECT * FROM user WHERE age IN (1, 2, 3)
    

    inSql 的方式:

    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.inSql(User::getAge, "1,2,3,4,5,6");
    
    -- 生成的 SQL
    SELECT * FROM user WHERE age IN (1, 2, 3, 4, 5, 6)
    

    从二者的方法签名也能看出来效果,in 接收的是 Collect 或 Object… 而 inSql 接收的是 String。

    eqSql

    适用于某一字段需要对比子查询的结果的情况。 Since 3.5.6 版本

    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.eqSql(User::getId, "select MAX(id) from table");
    
    -- 生成的 SQL
    SELECT * FROM user WHERE id = (select MAX(id) from table)
    

    还有类似的 gtSql、geSql、ltSql、leSql,Since 3.4.3.2 版本。

    但是要注意 SQL 注入问题,因为这里是直接插入到 SQL 语句中使用。

    having

    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.groupBy(User::getAge).having("sum(age) > {0}", 10);
    
    -- 生成的 SQL
    SELECT * FROM user GROUP BY age HAVING sum(age) > 10
    

    apply

    直接拼接 SQL 片段到查询条件中。

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.apply("date_format(dateColumn, '%Y-%m-%d') = {0}", "2008-08-08");
    
    -- 使用参数占位符生成的 SQL
    SELECT * FROM user WHERE date_format(dateColumn, '%Y-%m-%d') = '2008-08-08'
    

    推荐使用占位符的写法,防止 SQL 注入。

    last

    允许你直接在查询的最后添加一个 SQL 片段,而不受 MyBatis-Plus 的查询优化规则影响。这个方法应该谨慎使用,因为它可能会绕过 MyBatis-Plus 的查询优化。

    LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.last("limit 1");
    
    -- 生成的 SQL
    SELECT * FROM user LIMIT 1
    

    last 方法只能调用一次,多次调用将以最后一次为准。

    自定义 SQL

    允许在自定义的 SQL 中使用 Wrapper 的查询条件。 Since 3.0.7 版本。

    参数命名:在自定义 SQL 时,传递 Wrapper 对象作为参数时,参数名必须为 ew,或者使用注解 @Param(Constants.WRAPPER) 明确指定参数为 Wrapper 对象。

    使用 ${ew.customSqlSegment}:在 SQL 语句中,使用 ${ew.customSqlSegment} 来引用 Wrapper 对象生成的 SQL 片段。

    // Mapper 层编写自定义 SQL 语句
    public interface UserMapper extends BaseMapper<User> {
        @Select("SELECT * FROM user ${ew.customSqlSegment}")
        List<User> selectByCustomSql(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
    }
    
    // Service 层调用
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("name", "张三");
    
    List<User> userList = userMapper.selectByCustomSql(queryWrapper);
    

    也支持使用 XML 的方式调用查询条件

    
    

    其他

    @EnumValue

    当实体类中的某个字段是枚举类型时,使用@EnumValue注解可以告诉MyBatis-Plus在数据库中存储枚举值的哪个属性。

    @TableName("sys_user")
    public class User {
        @TableId
        private Long id;
        @TableField("nickname") // 映射到数据库字段 "nickname"
        private String name;
        private Integer age;
        private String email;
        private Gender gender; // 假设 Gender 是一个枚举类型
    }
    
    public enum Gender {
        MALE("M", "男"),
        FEMALE("F", "女");
    
        private String code;
        private String description;
    
        Gender(String code, String description) {
            this.code = code;
            this.description = description;
        }
    
        @EnumValue // 指定存储到数据库的枚举值为 code
        public String getCode() {
            return code;
        }
    }
    

    @TableLogic

    该注解用于标记实体类中的字段作为逻辑删除字段。开发者无需手动编写逻辑删除的代码,MyBatis-Plus 会自动处理这一过程。

    当执行查询操作时,MyBatis-Plus 会自动过滤掉标记为逻辑删除的记录,只返回未删除的记录。在执行更新操作时,如果更新操作会导致逻辑删除字段的值变为逻辑删除值,MyBatis-Plus 会自动将该记录标记为已删除。在执行删除操作时,MyBatis-Plus 会自动将逻辑删除字段的值更新为逻辑删除值,而不是物理删除记录。

    @TableName("sys_user")
    public class User {
        @TableId
        private Long id;
        @TableField("nickname") // 映射到数据库字段 "nickname"
        private String name;
        private Integer age;
        private String email;
        @TableLogic(value = "0", delval = "1") // 逻辑删除字段
        private Integer deleted;
    }
    

    @OrderBy

    该注解用于指定实体类中的字段在执行查询操作时的默认排序方式。如果没有显式指定排序条件,MyBatis-Plus 将按照注解中定义的排序规则返回结果。

    @TableName("sys_user")
    public class User {
        @TableId
        private Long id;
        @TableField("nickname") // 映射到数据库字段 "nickname"
        private String name;
        @OrderBy(asc = false, sort = 10) // 指定默认排序为倒序,优先级为10
        private Integer age;
        private String email;
    }
    

    sort 数字越小,优先级越高,即越先被应用。

    @OrderBy 注解的排序规则优先级低于在查询时通过 Wrapper 条件查询对象显式指定的排序条件。会被 Wrapper 指定的规则覆盖。

  • 相关阅读:
    js根据预设条件定义数组元素
    FinalShell安装和使用(用来连接远程Linux)
    C++继承、多继承及菱形继承
    工单提交管理H5小程序开发
    Linux中的服务管理
    【Unity HDRP渲染管线下的WorleyUtilities文件,“Hash”函数】
    Kubernetes leader election 源码分析
    JavaScript:实现Fedwick树算法(附完整源码)
    k8s node环境部署(三)
    ARM系列 -- 虚拟化(五)
  • 原文地址:https://blog.csdn.net/github_39423829/article/details/140357918