【Mybatis】MyBatis分页的三种实现方式,Log4j的使用

发布于:2025-08-05 ⋅ 阅读:(21) ⋅ 点赞:(0)

分页的实现

使用日志工厂看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组件….
  • 我们也可以控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

使用步骤:

  1. 导入log4j的包
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>
  1. 配置文件编写

没有编写 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
  1. setting设置日志实现
<settings>
  <setting name="logImpl" value="LOG4J"/>
</settings>
  1. 在程序中使用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();
}
  1. 测试,看控制台输出!
  • 使用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。
实现步骤:
  1. 修改Mapper文件,注意parameterType的数据类型,根据需要设置;
<select id="selectUser" parameterType="map" resultType="user">
  select * from user limit #{startIndex},#{pageSize}
</select>
  1. 前面Mybatis中使用的map,这边就用Mapper接口,参数为map
//选择全部用户实现分页
List<User> selectUser(Map<String,Integer> map);
  1. 在测试类中传入参数测试

思路:startIndex =(currentPage-1)*pageSize

  • startIndex:起始位置
  • currentPage:当前页面
  • pageSize:页面件数
  1. 转化为web使用时,需要传入的值是,当前页数每页的页面件数
  2. 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();
}

画面显示不只有做这些:

  1. 转化为web使用时,需要传入的值是,当前页数每页的页面件数
  2. map传入的起始位置是limit关键字 需要查询返回的第start~end条数据的起始数;
  3. 设置默认起始页为首页,设置每页显示件数,根据抽出 的所有数据计算totalPage(总页数),
  4. 总页数 = 总件数%页面件数 == 0 ?总件数/页面件数 :总件数/页面件数+1;
  5. totalPage总页数取得后,所需跳转页数与总页数判断,确保startIndex不会越界;
  6. 查询完结果后 将totalPage和 查询出的 数据一并返回至视图解析器
  7. 前端根据查询的数据进行显示,根据totalPage进行页码编辑;

经上述思路分析,不如PageHelper!!!

方式二:RowBounds分页(不推荐使用)

我们除了使用Limit在SQL层面实现分页,也可以使用RowBounds在Java代码层面实现分页,当然此种方式作为了解即可。

因为各方面问题,甚至于官方也不推荐。

  • 性能问题
  • 不适合复杂查询
  • 缺乏灵活性
  • 兼容性差

建立高效、稳定的数据库访问层才是持久层DB交互最终需要考虑的!

步骤:

  1. mapper接口
//选择全部用户RowBounds实现分页
List<User> getUserByRowBounds();
  1. Mybatis文件
<select id="getUserByRowBounds" resultType="user">
  select * from user
</select>
  1. 测试类

在这里,我们需要使用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的配置选一个就可以;

  1. 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=mysql
            reasonable=true
            supportMethodsArguments=true
            params=count=countSql
            autoRuntimeDialect=true
          </value>
        </property>
      </bean>
    </array>
  </property>
</bean>
  1. 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 进行分页查询
  1. 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;
}
  1. Controller层代码实现逻辑
    1. 返回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";
}
  1. 前端页面显示
    1. 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>
页面显示如下
  1. 第一页
  2. 第二页
优化分页内容显示
  1. 使用BootStarp的式样导入,

使用pagination显示叠加样式;

除了pagination 还有pager

  1. 增加 循环遍历显示页数 ,根据页码指定跳转式样

思路:

1. foreach遍历条数,起始:1,结束:总页数;
2. 当前页高亮显示,其他页默认显示

效果如下:

页面显示效果:


网站公告

今日签到

点亮在社区的每一天
去签到