【Mybatis】MyBatis分页的三种实现方式,Log4j的使用
文章目录
- 分页的实现
- 使用日志工厂看Log信息
- Log4j
- 方式一:SQL的`limit`关键字
- SQL中`Limit`关键字的用法
- 实现步骤:
- 方式二:RowBounds分页(不推荐使用)
- 方式三:PageHelper
- 引入依赖
- 配置plugins
- 使用 PageHelper 进行分页查询
- 页面显示如下
- 优化分页内容显示
分页的实现
使用日志工厂看Log信息
思考:我们在测试SQL的时候,要是能够在控制台输出 SQL 的话,是不是就能够有更快的排错效率?
如果一个 数据库相关的操作出现了问题,我们可以根据输出的SQL语句快速排查问题。
对于以往的开发过程,我们会经常使用到debug模式来调节,跟踪我们的代码执行过程。但是现在使用
Mybatis
是基于接口
,配置文件
的源代码执行过程。
我们必须选择日志工具来作为我们开发,调节程序的工具。
Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
- SLF4J
- Apache Commons Logging
Log4j 2
- Log4j
- JDK logging
具体选择哪个日志实现工具由MyBatis的内置日志工厂确定。它会使用最先找到的(按上文列举的顺序查找)。 如果一个都未找到,日志功能就会被禁用。
标准日志实现
指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。
<settings><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
测试,可以看到控制台有大量的输出!我们可以通过这些输出来判断程序到底哪里出了Bug
Log4j
简介:
Log4j
是Apache的一个开源项目- 通过使用
Log4j
,我们可以控制日志信息输送的目的地:控制台
,文本
,GUI组件…. - 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
使用步骤:
- 导入
log4j
的包
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
- 配置文件编写
没有编写 log4j
的配置文件,Mybatis的log依旧打印出来了,,配置文件是在程序执行时需要用到的;
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
- setting设置日志实现
<settings><setting name="logImpl" value="LOG4J"/>
</settings>
- 在程序中使用Log4j进行输出!
如果需要控制台打印的话 需要new一个Logger
对象,这样才能输出出来
//注意导包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(MyTest.class);@Test
public void selectUser() {logger.info("info:进入selectUser方法");logger.debug("debug:进入selectUser方法");logger.error("error: 进入selectUser方法");SqlSession session = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);List<User> users = mapper.selectUser();for (User user: users){System.out.println(user);}session.close();
}
- 测试,看控制台输出!
- 使用
Log4j
输出日志 - 可以看到还生成了一个日志的文件 【需要修改file的日志级别】
方式一:SQL的limit
关键字
思考:为什么需要分页?
在学习mybatis等持久层框架的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,如果查询大量数据的时候,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。
SQL中Limit
关键字的用法
#语法
SELECT * FROM table LIMIT stratIndex,pageSize;SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15 #为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. #如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行 #换句话说,LIMIT n 等价于 LIMIT 0,n。
实现步骤:
- 修改Mapper文件,注意
parameterType
的数据类型,根据需要设置;
<select id="selectUser" parameterType="map" resultType="user">select * from user limit #{startIndex},#{pageSize}
</select>
- 前面Mybatis中使用的
map
,这边就用Mapper
接口,参数为map
//选择全部用户实现分页
List<User> selectUser(Map<String,Integer> map);
- 在测试类中传入参数测试
思路:startIndex =(currentPage-1)*pageSize
- startIndex:起始位置
- currentPage:当前页面
- pageSize:页面件数
- 转化为web使用时,需要传入的值是,
当前页数
和每页的页面件数
;- map传入的起始位置是
limit
关键字 需要查询返回的第start~end条数据的起始数;
//分页查询 , 两个参数startIndex , pageSize
@Test
public void testSelectUser() {SqlSession session = MybatisUtils.getSession();UserMapper mapper = session.getMapper(UserMapper.class);int currentPage = 1; //第几页int pageSize = 2; //每页显示几个Map<String,Integer> map = new HashMap<String,Integer>();map.put("startIndex",(currentPage-1)*pageSize);map.put("pageSize",pageSize);List<User> users = mapper.selectUser(map);for (User user: users){System.out.println(user);}session.close();
}
画面显示不只有做这些:
- 转化为web使用时,需要传入的值是,
当前页数
和每页的页面件数
;- map传入的起始位置是
limit
关键字 需要查询返回的第start~end条数据的起始数;- 设置默认起始页为首页,设置每页显示件数,根据抽出 的所有数据计算
totalPage
(总页数),- 总页数 = 总件数%页面件数 == 0 ?总件数/页面件数 :总件数/页面件数+1;
totalPage
总页数取得后,所需跳转页数与总页数判断,确保startIndex
不会越界;- 查询完结果后 将
totalPage
和 查询出的 数据一并返回至视图解析器
;- 前端根据查询的数据进行显示,根据
totalPage
进行页码编辑;
经上述思路分析,不如PageHelper
!!!
方式二:RowBounds分页(不推荐使用)
我们除了使用Limit
在SQL层面实现分页,也可以使用RowBounds
在Java代码层面实现分页,当然此种方式作为了解即可。
因为各方面问题,甚至于官方也不推荐。
- 性能问题
- 不适合复杂查询
- 缺乏灵活性
- 兼容性差
建立高效、稳定的数据库访问层才是持久层DB交互最终需要考虑的!
步骤:
- mapper接口
//选择全部用户RowBounds实现分页
List<User> getUserByRowBounds();
- Mybatis文件
<select id="getUserByRowBounds" resultType="user">select * from user
</select>
- 测试类
在这里,我们需要使用RowBounds
类
@Test
public void testUserByRowBounds() {SqlSession session = MybatisUtils.getSession();int currentPage = 2; //第几页int pageSize = 2; //每页显示几个RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);//通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);for (User user: users){System.out.println(user);}session.close();
}
方式三:PageHelper
了解即可,可以自己尝试使用
官方文档:https://pagehelper.github.io/
具体使用方法:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
引入依赖
<!-- 引入 PageHelper 使用Springboot -->
<!-- <dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
--><!-- 如果你不使用 Spring Boot,使用SpringMVC可使用: -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.3</version>
</dependency>
<!-- 最新版 : -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>6.1.0</version>
</dependency>
配置plugins
Spring的配置和Mybatis的配置选一个就可以;
- Spring的配置
引入到SqlSessionFactoryBean
中,使用Interceptor
类型
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="configLocation" value="classpath:mybatis-config.xml"/><!-- 导入pageHelper分页 --><property name="plugins"><array><bean class="com.github.pagehelper.PageInterceptor"><property name="properties"><value>helperDialect=mysqlreasonable=truesupportMethodsArguments=trueparams=count=countSqlautoRuntimeDialect=true</value></property></bean></array></property>
</bean>
- mybatis-config.xml
<configuration><!-- 插件配置:PageHelper 分页插件 --><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><property name="helperDialect" value="mysql"/><property name="reasonable" value="true"/><property name="supportMethodsArguments" value="true"/><property name="params" value="count=countSql"/></plugin></plugins></configuration>
使用 PageHelper 进行分页查询
- Service层实现代码逻辑
@Override
public PageInfo<User> getUserList(int pageNum, int pageSize) {// 开始分页:第 pageNum 页,每页 pageSize 条PageHelper.startPage(pageNum, pageSize);// 执行查询(这个查询会被自动分页)List<User> users = userMapper.getUserList();// 封装成 PageInfo 对象,包含分页信息PageInfo<User> pageInfo = new PageInfo<>(users);System.out.println("pageInfo {}:" + pageInfo);return pageInfo;
}
- Controller层代码实现逻辑
- 返回JSON,前端使用Ajax处理
@RequestMapping("/getUserList")
@ResponseBody
public Object getUserList( @RequestParam(defaultValue = "1") int pageNum,@RequestParam(defaultValue = "10") int pageSize) {PageInfo<User> pageInfo = userService.getUserList(pageNum,pageSize);return ResponseEntity.ok(pageInfo);
}
2. 返回视图解析的网站地址,使用`JSP`显示`ModelView`的数据
@RequestMapping("/getUserList")
public Object getUserList( Model model,@RequestParam(defaultValue = "1") int pageNum,@RequestParam(defaultValue = "10") int pageSize) {PageInfo<User> pageInfo = userService.getUserList(pageNum,pageSize);model.addAttribute("pageInfo",pageInfo);model.addAttribute("userList",pageInfo.getList());model.addAttribute("currentPage", pageInfo.getPageNum());model.addAttribute("totalPages", pageInfo.getPages());model.addAttribute("pageSize", pageInfo.getPageSize());return "userList";
}
- 前端页面显示
- JSP显示
<c:if test="${currentPage > 1}">
<a href="?pageNum=${currentPage - 1}&pageSize=${pageSize}">上一页</a>
</c:if><span> 第 ${currentPage} 页,共 ${totalPages} 页 </span><c:if test="${currentPage < totalPages}">
<a href="?pageNum=${currentPage + 1}&pageSize=${pageSize}">下一页</a>
</c:if>
配合`set`标签使用,明细显示行号
<%-- 计算当前行的编号--%>
<c:set var="index" value="${(currentPage - 1) * pageSize + status.index}" />
<tbody>
<c:forEach items="${userList}" var="user" varStatus="status">
<%-- 计算当前行的编号--%>
<c:set var="index" value="${(currentPage - 1) * pageSize + status.index}" /><tr>
<td>${index+1}</td>
<td>${user.userCode}</td>
<td>${user.userName}</td>
<td>${user.gender}</td>
<td>${user.phone}</td>
<td>${user.address}</td>
<td>
<a class="btn btn-primary" href="/user/modifyUser?id=${user.id}">修改</a>
<a class="btn btn-danger" href="/user/deleteUser?id=${user.id}">删除</a>
<a class="btn btn-success" href="/user/viewUser?id=${user.id}">查看</a>
</td>
</c:forEach>
</tbody>
页面显示如下
- 第一页
- 第二页
优化分页内容显示
- 使用BootStarp的式样导入,
使用pagination
显示叠加样式;
除了pagination
还有pager
- 增加 循环遍历显示页数 ,根据页码指定跳转式样
思路:
1. foreach遍历条数,起始:1,结束:总页数;
2. 当前页高亮显示,其他页默认显示
效果如下:
页面显示效果: