MyBatis入门实验(10)之分页查询

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gongm24/article/details/81102131

实验内容

在mysql中,写一个分页语句非常简单,比如原查询语句为

select * from user

那么查询第一页,每页5条数据,其语句如下

select * from user limit 1, 5

通常在分页的时候,页面还需要显示总记录条数

select count(1) from (select * from user) ooxx

所以要进行分页查询,需要执行以下三步:

  1. 执行分页查询,查询出当前页的数据
  2. 执行count查询,查询总记录条数,以此可以计算出总页数
  3. 将前两步查询的数据封装成一个对象进行返回

操作步骤

一、安装

添加Maven依赖(本文使用版本为3.4.6)

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>x.x.x</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.42</version>
</dependency>

二、创建数据库及表结构

分别创建用户表、角色表以及用户角色关联表,一个用户可以属于多个角色,一个角色也可以包含多个用户

CREATE TABLE `user` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(32) NOT NULL COMMENT '用户名',
  `password` varchar(64) NOT NULL COMMENT '密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT '用户';

初始化数据

delete from `user`;
insert into `user` values (1, 'user1', '123');
insert into `user` values (2, 'user2', '123');
insert into `user` values (3, 'user3', '123');
insert into `user` values (4, 'user4', '123');
insert into `user` values (5, 'user5', '123');
insert into `user` values (6, 'user6', '123');
insert into `user` values (7, 'user7', '123');
insert into `user` values (8, 'user8', '123');
insert into `user` values (9, 'user9', '123');
insert into `user` values (10, 'user10', '123');

三、创建 Mybatis 配置文件

src/main/resources 目录下创建 mybatis-config.xml 文件,内容如下

中间多了一段 plugins 配置,用于配置一个分页拦截器,具体在后面还有说明

<configuration>
    <properties resource="jdbc.properties"></properties>

    <plugins>
        <plugin interceptor="tutorial.mybatis.interceptor.PageInterceptor" />
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 加载XML,同时加载接口类 -->
    <mappers>
        <mapper class="tutorial.mybatis.mapper.UserMapper"></mapper>
        <mapper resource="mybatis/User.xml"></mapper>
    </mappers>
</configuration>

src/main/resources 目录下创建 jdbc.properties 文件,内容如下

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tutorial_mybatis?characterEncoding=utf-8&useSSL=true
jdbc.username=root
jdbc.password=

四、创建实体类

创建包 tutorial.mybatis.model,并在该包下创建 User 类,内容如下

其中,Topic 类中添加了一个 userList 属性,用于存储用户信息

public class User {

    private Long id;

    private String username;

    private String password;

    // 省略 get / set 方法
}

src/main/resources 目录下创建目录 mybatis,并在该目录下创建 User.xml,内容如下

User.xml

<mapper namespace="tutorial.mybatis.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="tutorial.mybatis.model.User">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="username" jdbcType="VARCHAR" property="username" />
        <result column="password" jdbcType="VARCHAR" property="password" />
    </resultMap>

    <select id="listAll" resultMap="BaseResultMap">
        SELECT a.id, a.username, a.password
            FROM `user`
    </select>

</mapper>

五、创建分页类

public class Page<T> {

    private int page;

    private int pageSize;

    private int totalPage;

    private int totalRow;

    private List<T> rows;

    // ...省略 get / set 方法
}

六、创建接口类

创建包 tutorial.mybatis.mapper,并在该包下创建接口 UserMapper,内容如下

入参为分页对象,里面包含了当前页码及每页记录数

public interface UserMapper {

    List<User> listByPage(Page page);

}

七、创建分页拦截器

创建包 tutorial.mybatis.interceptor,并在该包下创建类 PageInterceptor,内容如下

在第三步中,声明了这个拦截器,这里进行拦截器的具体设置

@Intercepts 注解用于声明拦截位置,这里拦截的是 StatementHandler 类的 prepare 方法,因为 prepare 方法可能存在多个重载方法,所以需要指定 args 的参数类型以确定具体拦截的是哪一个方法。

本文中拦截了所有 ByPage 结束的方法,并重新组装SQL进行查询

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class PageInterceptor implements Interceptor {

    private static String dialect = "";
    private static String pageSqlId = "";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (RoutingStatementHandler) invocation.getTarget();
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // 拦截所有以ByPage结束的查询方法
        if (mappedStatement.getId().matches(".+ByPage$")) {
            BoundSql boundSql = statementHandler.getBoundSql();
            // 获取原始SQL
            String sql = boundSql.getSql();
            // 生成查询总条数SQL语句
            String countSql = "select count(1) from (" + sql + ") xxox";
            // 执行总条数SQL语句的查询
            Connection connection = (Connection)invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);
            //获取参数信息即where语句的条件信息,注意上面拿到的sql中参数还是用?代替的
            ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);
            ResultSet rs = countStatement.executeQuery();
            int count = 0;
            if (rs.next()) {
                count = rs.getInt(1);
            }
            rs.close();
            countStatement.close();

            if (boundSql.getParameterObject() instanceof Page) {
                Page page = ((Page) boundSql.getParameterObject());
                page.setTotalRow(count);
                // 改造后带分页查询的SQL语句
                String pageSql = sql + " limit " + page.getPage() + "," + page.getPageSize();
                System.out.println("执行SQL:" + pageSql);
                metaObject.setValue("delegate.boundSql.sql", pageSql);
            }
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

六、构建

准备工作就绪,开始最终章,创建启动类 MybatisConfig,内容如下:

public class MybatisConfig {

    private static SqlSessionFactory sqlSessionFactory;
    private static Reader reader;

    static {
        try {
            reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        SqlSession session = sqlSessionFactory.openSession();
        try {
            listUser(session);
        } finally {
            session.close();
        }
    }

    /**
     * 查询用户
     */
    public static void listUser(SqlSession session) {
        UserMapper userMapper = session.getMapper(UserMapper.class);
        System.out.println("------- 获取用户列表 --------");
        // 查询第一页,每页5条记录
        printUser(userMapper.listByPage(new Page<User>() {{
            setPage(1);
            setPageSize(5);
        }}));
    }

    private static void printUser(List<User> list) {
        if (list != null && !list.isEmpty()) {
            for (User user : list) {
                printUser(user);
            }
        }
    }

    private static void printUser(User user) {
        if (user == null) {
            System.out.println("没有找到数据");
        } else {
            String userInfo = "ID:" + user.getId() + "名字:" + user.getUsername()+", 密码:" + user.getPassword();
            System.out.println(userInfo);
        }
    }
}

打印结果为:

------- 获取用户列表 --------
ID:1名字:user1, 密码:123
ID:2名字:user2, 密码:123
ID:3名字:user3, 密码:123
ID:4名字:user4, 密码:123
ID:5名字:user5, 密码:123

参考 https://blog.csdn.net/wf787283810/article/details/77847576

猜你喜欢

转载自blog.csdn.net/gongm24/article/details/81102131