mybatis:用SelectProvider注解的方法使用RowBounds及其子类型的参数出错

问题现象

mybatis的org.apache.ibatis.session.RowBounds类含有offset和limit属性,限制从数据库结果集的哪一行开始,最多返回多少行。
但在mapper接口的方法中,如果方法被SelectProvider注解,传递RowBounds及其子类型的参数会出错。

示例:
mapper接口的代码如下,其中selectManyUsers方法用SelectProvider注解,并且含有一个RowBounds 类型的参数:

package com.thb.mapper;

import java.util.List;

import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.session.RowBounds;

import com.thb.model.User;

public interface UserMapper {

    @Results(value = {
        @Result(property = "id", column = "id", id = true),
        @Result(property = "userName", column = "user_name"),
        @Result(property = "homeTown", column = "home_town"),
        @Result(property = "type", column = "type"),
    })
    @SelectProvider(type = UserSqlBuilder.class, method = "selectManyUsers")
    List<User> selectManyUsers(RowBounds rowBounds);

    public static class UserSqlBuilder {
        public static String selectManyUsers(final RowBounds rowBounds) {
            return new SQL() {{
                SELECT("id, user_name, home_town, type");
                FROM("user");
                WHERE("type = #{type}");
                //WHERE("home_town = #{homeTown}");
                OFFSET(rowBounds.getOffset());
                LIMIT(rowBounds.getLimit());
            }}.toString();
        }
    }
}

调用代码:

// 取得一个SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper userMapper = session.getMapper(UserMapper.class);

    RowBounds rowBounds = new RowBounds(0, 1);
    List<User> users = userMapper.selectManyUsers(rowBounds);
    for (User user : users) {
        System.out.println("*".repeat(60));
        System.out.println("id = " + user.getId());
        System.out.println("userName = " + user.getUserName());
        System.out.println("homeTown = " + user.getHomeTown());
        System.out.println("type = " + user.getType());
    }

运行报错,提示参数为null,引用的时候出现了空指针异常:
在这里插入图片描述

原因分析

用debug模式,通过堆栈分析,发现mybatis在处理的过程中,会检查方法有没有RowBounds及其子类型的参数,有的话会单独提取出来,没有传递给sql provider的方法,所以在sql provider的方法内无法使用RowBounds及其子类型的参数的值。

执行到CachingExecutor的query方法的时候,RowBounds参数的值还是存在的:
在这里插入图片描述

将RowBounds及其子类型的参数提取出来:
在这里插入图片描述

调用sql privider方法的时候,没有传递RowBounds及其子类型的参数:
在这里插入图片描述

参数为null:
在这里插入图片描述

参数为null:
在这里插入图片描述

等执行到sql provider的方法的时候,RowBounds类型的参数为null,所以在方法内使用抛出空指针异常:
在这里插入图片描述

解决方法

可以在sql provider的方法中,使用两个整型参数offset和limit,绕过这个问题。
或者自己写一个类,里边有两个属性,分别是offset和limit。但注意自己写的类不要继承RowBounds。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、使用 SelectProvider 进行 left join Mybatis Plus 提供了一个 SelectProvider 类,可以动态生成 SQL 语句。在 left join 操作中,我们可以使用 SelectProvider 来实现。 例如,我们有两个表,一个是用户表 user,另一个是订单表 order。我们想要查询某个用户的所有订单信息,可以使用 left join 来实现。 首先,我们需要定义一个查询语句的模板,使用 @SelectProvider 注解来指定: ``` @SelectProvider(type = MyProvider.class, method = "selectUserOrders") List<UserOrder> selectUserOrders(@Param("userId") Long userId); ``` 其中,MyProvider 是我们定义的一个 SelectProvider 类,selectUserOrders 是其中的一个方法,用来生成查询语句。 然后,在 MyProvider 中,我们需要实现 selectUserOrders 方法,生成查询语句: ``` public String selectUserOrders(@Param("userId") Long userId) { return new SQL(){{ SELECT("user.*, order.*"); FROM("user"); LEFT_JOIN("order ON user.id = order.user_id"); WHERE("user.id = #{userId}"); }}.toString(); } ``` 在这个方法中,我们使用 SQL 类来生成查询语句。首先,使用 SELECT 方法指定要查询的字段,使用 FROM 方法指定主表,使用 LEFT_JOIN 方法来进行左连接操作,使用 WHERE 方法来指定查询条件。 2、使用分页插件进行分页查询 Mybatis Plus 提供了一个分页插件,可以方便地实现分页查询。 首先,我们需要在配置文件中开启分页插件: ``` <plugins> <plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"> <property name="dialectType" value="mysql"/> </plugin> </plugins> ``` 然后,在查询方法中,我们可以使用 Page 类来进行分页查询: ``` Page<UserOrder> page = new Page<>(1, 10); List<UserOrder> userOrders = userOrderMapper.selectUserOrders(page, userId); ``` 其中,Page 的第一个参数是当前页码,第二个参数是每页显示的记录数。userOrderMapper 是我们定义的一个 Mapper 接口,selectUserOrders 是其中的一个方法,用来进行查询操作。 在 selectUserOrders 方法中,我们需要使用 Mybatis Plus 提供的分页参数注解 @Param 来指定分页参数: ``` List<UserOrder> selectUserOrders(@Param("page") Page<UserOrder> page, @Param("userId") Long userId); ``` 然后,在 SQL 语句中,我们可以使用 Mybatis Plus 提供的分页语句来进行分页操作: ``` public String selectUserOrders(@Param("page") Page<UserOrder> page, @Param("userId") Long userId) { return new SQL(){{ SELECT("user.*, order.*"); FROM("user"); LEFT_JOIN("order ON user.id = order.user_id"); WHERE("user.id = #{userId}"); }}.toString() + " LIMIT " + page.getOffset() + ", " + page.getSize(); } ``` 在这个方法中,我们需要使用 Page 类提供的 getOffset 和 getSize 方法来获取当前分页的偏移量和每页显示的记录数,然后将它们拼接到 SQL 语句的末尾。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值