四、Mybatis 结果集映射、日志和分页

5、解决属性名和字段名不一致的问题(ResultMap)

我们复制一份上面的项目,名字叫项目2,在项目2中做一点更改。

1、问题

在项目1中,我们的实体类pojo/User中的属性是和数据库中的字段一一对应的

四、Mybatis 结果集映射、日志和分页

在项目2中,我们修改实体类的pwd属性为password,重新生成构造方法和getter和setter,现在实体类中的属性与数据库中的字段不能完全匹配上了。

四、Mybatis 结果集映射、日志和分页

这是我们不做其他的修改,运行根据id查询用户信息的方法,查看结果:四、Mybatis 结果集映射、日志和分页

我们发现测试方法虽然可以正常执行,但是,password字段为null了,这是为什么?

2、解决方案

首先来看上面password字段变为了空的原因。

在UserMapper.xml中根据id查询用户信息是这个sql

<select id="getUserById" parameterType="int" resultType="user">
  select * from mybatis.user where id = #{id};
</select>

我们转换一下,实际查询的是这个

<select id="getUserById" parameterType="int" resultType="user">
  select id,name,pwd from mybatis.user where id = #{id};
</select>

这就不难看出,因为pwd可以从数据库中查出,但是User对象中却不是这个字段,而是password,因此password就没有值了所以为空。

2.1、解决方案一

既然在查询的结果中没有password字段,那我们就把pwd重命名为password,让password这个字段存在。我们修改UserMapper.xml中的查询sql:

<select id="getUserById" parameterType="int" resultType="user">
  select id,name,pwd as password from mybatis.user where id = #{id};
</select>

再运行测试方法,发现password结果可以正常展示了

四、Mybatis 结果集映射、日志和分页

2.2、解决方案二

虽然上面的方法有效,但是略显简单粗暴了点,Mybatis中可以使用ResultMap来对变量做映射关系。

我们修改UserMapper.xml中的mapper如下:

<mapper namespace="com.luca.dao.UserMapper">
    <resultMap id="userResultMap" type="user">
<!--column指的是数据库中的字段名,property指的是实体类中的属性名-->
        <result column="pwd" property="password" />
    </resultMap>
    
    <select id="getUserById" parameterType="int" resultType="user" resultMap="userResultMap">
        select * from mybatis.user where id = #{id};
    </select>

</mapper>

在mapper中新建了一个resultMap,命名为userResultMap,在里面配置了数据库字段pwd和实体类属性password的映射关系,然后在select 中指定使用的resultMap为它。

这样我们重新运行下测试方法,password也可以正常查询出来。

6、日志

在前面的例子中我们一直都是使用sout的方式打印我们需要的信息,但是这样的方式既不够详细也不够规范。在下面我们引入日志的方式来打印需要展示的信息。

首先复制一份上面例子的module,避免代码杂乱,同样的,针对com.luca.dao下的UserMapper创建测试方法,确保测试方法正常运行。

拷贝出来的代码结构如下:

四、Mybatis 结果集映射、日志和分页

我么再查看Mybatis的官方文档,其中就有关于日志的配置,其中logImpl就是用来配置日志的。

四、Mybatis 结果集映射、日志和分页

文档中列出了这些可配置的日志选项,我们下面会介绍Log4j和STDOUT_LOGGING两种方式:

  • SLF4J
  • LOG4J *
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING *
  • NO_LOGGING

6.1、日志工厂

我们先看比较简单的STDOUT_LOGGING方式,首先我们需要在mybatis-config.xml中增加配置

<settings>
		<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

注意:setting标签需要放在properties和typeAliases标签中间,否则IDE会报红提示

不需要做其他的配置,我们再次运行test下的单元测试方法,查看输出的结果:

四、Mybatis 结果集映射、日志和分页

这次输出的结果不仅仅有数据库查询的结果,还有很多其他的信息,mybatis在查询出数据前后做了很多其他的工作:打开JDBC连接、创建连接、关闭自动提交、preparing的sql语句、sql查询的参数、查询出数据、关闭连接、归还连接池......

可以看到,在console中输出了比原来详细的多的信息。

6.2、Log4j

1. Log4j是什么

Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。-- 百度百科

从百度百科的解释中可以大概看出log4j:

  1. 是Apache的开源项目
  2. 可以控制输出日志到控制台、文件等等
  3. 可以配置每一条日志的输出格式和级别
  4. 通过配置文件来实现,不需要修改应用的代码

2. 使用Log4j

下面我们尝试在现在的模块中使用log4j,首先必不可少的当然是导包:

pom.xml

<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.12</version>
</dependency>

然后我们在resources下创建log4j的配置文件:

log4j.properties

### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=logs/debug.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/luca.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =logs/luca.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

最后在mybatis-config.xml中修改setting使用的日志方式为log4j

<settings>
  <setting name="logImpl" value="LOG4J"/>
</settings>

好了,我们再运行下测试方法:

四、Mybatis 结果集映射、日志和分页

可以看到,console中同样打印出了十分详细的信息,并且是按照我们配置文件中设置的格式输出。另外,在项目的根目录下,可以看到创建了一个logs目录,下面存放了对应的debug和error级别的日志。

除了打印mybatis的debug日志,我们还可以在自己打印需要的信息,创建测试方法如下:

package com.luca.dao;

import com.luca.dao.UserMapper;
import com.luca.pojo.User;
import com.luca.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;


public class TestUserMapper {
    static Logger logger = Logger.getLogger(TestUserMapper.class);

    @Test
    public void TestLog4jOutput() {
        logger.info("This is a info level info");
        logger.debug("This is a debug level info");
        logger.error("This is a error level info");
    }
}

我们在测试方法中输出了不同级别的信息,需要注意的是Logger引用的是log4j.Logger,否则会有问题。运行测试方法,在console中和logs/luca.log中都可以看到我们打印的信息。

四、Mybatis 结果集映射、日志和分页

7、分页

7.1、Limit实现分页

看到分页首先想到的就是下面这样的SQL语句,那么在Mybatis中实现分页也就是这样的一句sql:

select * from user limit 0, 2;

还是三步走:

  1. 创建UserMapper接口

    com/lucal/dao/UserMapper

    //分页查询用户
    List<User> getUserByLimit(Map<String, Integer> map);
    
  2. 实现UserMapper.xml文件

    com/lucal/dao/UserMapper.xml

    <select id="getUserByLimit" parameterType="map" resultMap="userResultMap">
      select * from mybatis.user limit #{startIndex}, #{pageSize}
    </select>
    

    在这里我们传递参数使用的是前面提到的”万能的Map“,其中传入分页查询的开始下标和查询大小。

  3. 测试

    test/com/luca/dao/TestUserMapper

    @Test
    public void TestGetUserByLimit() {
      SqlSession sqlSession = MybatisUtils.getSqlSession();
      UserMapper mapper = sqlSession.getMapper(UserMapper.class);
      HashMap<String, Integer> map = new HashMap<>();
      map.put("startIndex", 0);
      map.put("pageSize", 2);
      List<User> userList = mapper.getUserByLimit(map);
      for (User user : userList) {
        System.out.println(user);
      }
      sqlSession.close();
    }
    

    执行测试方法,可以看到查询的结果和输入的分页参数预期结果一致:

    四、Mybatis 结果集映射、日志和分页

7.2、RowBounds实现分页

除了使用上面手写limit语句进行分页,Mybatis中内置了RowBounds方式进行分页,但是由于这种方式是查询出所有的数据再进行切分来实现分页的,所以在查询数据量大的时候并不建议使用它。我们直接来看使用方法,只要在接口中传入一个RowBounds对象即可:

UserMapper.java

//使用RowBounds分页查询用户
List<User> getUserByRowBounds(RowBounds rowBounds);

UserMapper.xml

<select id="getUserByRowBounds" resultMap="userResultMap">
  select * from mybatis.user
</select>

TestUserMapper.java

@Test
public void TestGetUserByRowBounds() {
  SqlSession sqlSession = MybatisUtils.getSqlSession();
  UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  List<User> users = mapper.getUserByRowBounds(new RowBounds(3, 2));
  for (User user : users) {
    System.out.println(user);
  }
  sqlSession.close();
}

7.3、PageHelper实现分页

除了上面两种方式,在企业中也有很多使用PageHelper进行分页,这里不做介绍,等有需要的时候跟着官方文档学习吧~

官网:https://pagehelper.github.io

上一篇:Mybatis框架(二)—简单的增删改查


下一篇:Mybatis 从入门到入土