实验内容
在mysql中,写一个分页语句非常简单,比如原查询语句为
select * from user
那么查询第一页,每页5条数据,其语句如下
select * from user limit 1, 5
通常在分页的时候,页面还需要显示总记录条数
select count(1) from (select * from user) ooxx
所以要进行分页查询,需要执行以下三步:
- 执行分页查询,查询出当前页的数据
- 执行count查询,查询总记录条数,以此可以计算出总页数
- 将前两步查询的数据封装成一个对象进行返回
操作步骤
一、安装
添加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