MyBatis学习随笔(3)—— ResultMap、日志、分页

前言

上篇文章主要是对Mybatis的增删改查以及核心配置解析的了解。本篇文章将堆SQL语句进行分析,主要是对结果集映射的了解,同时还有怎样配置Mybatis日志、分页如何处理等等。

结果集映射——ResultMap

结果集映射顾名思义就是对结果集进行一系列的处理,得到我们想要的数据。在SQL查询,尤其是复杂查询中,所得出来结果的列名在映射实体类中并不存在,导致在Java业务层中无法得到对应数据,这种情况就需要结果集映射来完成,简单来说就是为结果列名取别名,使得查询出来的结果类名能够对应上实体类上的属性名。
userMapper.java文件

public interface userMapper {
    //设计场景:查询用户表所有用户的所有信息,要求查询出来的列名使用中文
    public List<User> addUserList();
}

userMapper.xml文件

    <select id="addUserList" resultMap="userMapper">
        select id '主键', name '用户名', pwd '密码' from user;
    </select>

异常:

java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.mybatis.dao.userMapper.userMapper

有上述代码可以看到,并没有设置resultType,同时也报了异常,异常的意思是“结果映射集合不包含的值”,出现这个异常大概率是结果集找不到对应的映射内容,所以需要配置resultMap标签。

    <resultMap id="userMapper" type="user">
        <result property="id" column="主键"/>
        <result property="name" column="用户名"/>
        <result property="pwd" column="密码"/>
    </resultMap>

resultMap的要求是id需要和对应select标签的resultMap一样,而type属性要求是返回的类型,而resultMap的作用就是给列和属性名进行映射,将属性名和当前select语句查询出来的表的列名一一对应,这样后续在使用时能够有值。

测试.java:

    @Test
    public void ResultMapperTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        userMapper mapper = sqlSession.getMapper(userMapper.class);
        List<User> users = mapper.addUserList();
        for(User user : users){
            System.out.println(user.toString());
        }
    }

日志

在Mybatis开发中难免会出现以下不易察觉的错误,尤其是SQL语句的错误,曾经我就因为把where错写成when,让我找错误找了半天。这种情况需要日志来排查,Mybatis开启日志非常简单,需要在核心配置文件的setting中设置开启即可。
mybatis-config.xml文件:

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

运行结果:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 708890004.
==>  Preparing: select id '主键', name '用户名', pwd '密码' from user;
==> Parameters: 
<==    Columns: 主键, 用户名, 密码
<==        Row: 1, 枫华, 123456
<==        Row: 3, 轩五, 123456
<==        Row: 4, 天使, 1614700
<==      Total: 3
User(id=1, name=枫华, pwd=123456)
User(id=3, name=轩五, pwd=123456)
User(id=4, name=天使, pwd=1614700)

从上述运行结果中发现日志能够把SQL语句以及结果很清晰的复现出来,甚至还将查询出来的表的信息发了出来。这是运行成功的结果,如果出现异常日志会怎样分析呢?
userMapper.xml文件

    <select id="selectUser" resultType="user" parameterType="int">
        select id ids from user where id=#{id}
    </select>

IDEA给的异常信息:

java.lang.NullPointerException
	at MybatisTest.selectById(MybatisTest.java:26)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

像这种因为属性映射问题IDEA给的异常信息很模糊,因为这本质上来讲不算异常,SQL语句查出来了,只是不知道往哪放而已。有的时候什么因为映射不成功出现空指针也未可知,程序员这个时候往往项目到是SQL语句的错误,这时候日志的辅助工作就显得尤为重要。
日志:

PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1485697819.
==>  Preparing: select id ids from user where id=?
==> Parameters: 1(Integer)
<==    Columns: ids
<==        Row: 1
<==      Total: 1

java.lang.NullPointerException
	at MybatisTest.selectById(MybatisTest.java:26)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

开头的SQL语句以及查询出来的结果很容易就可以让人发现错误所在。

Log4j日志

Log4j日志是比较常使用的日志插件,在mybatis中使用日志插件也是需要配置,与STDOUT_LOGGING相比,难点在于Log4j的配置,但是Log4j功能也更全。

第一步:导入依赖,想要使用Log4j,就先需要导入Log4j的依赖或者jar包

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

第二步:在核心配置文件中的settings中设置日志value为LOG4J,注意这个value必须一模一样,多一个空格都不行

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

第三步:创建log4j.properties配置文件,对log4j进行功能配置

######################## 将等级为DEBUG的日志信息输出到consoleh和file两个目的地, console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

########################控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
#在控制台输出
log4j.appender.console.Target = System.out
#在DEBUG级别输出
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

第三步:使用

    public static final Logger logger = LoggerFactory.getLogger(MybatisTest.class);

分页

mybatis的分页其实可以采用原始SQL语句的方式,比较特殊的就是多了一些分页的方法,比如RowboundsPageHelper
在本篇文章中只说明limit和Rowbounds,因为PageHelper插件需要Spring。

limit

userMapper.java

public interface userMapper {
    //使用limit完成分页
    //start表示从哪里开始分页,pageSize表示每页有多少记录
    public List<User> userListByLimit(@Param("start") int start, @Param("pageSize") int PageSize);
}

userMapper.xml

    <select id="userListByLimit" resultType="user">
        select * from user limit #{start}, #{pageSize};
    </select>

测试:

    @Test
    public void userListByLimitTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        userMapper mapper = sqlSession.getMapper(userMapper.class);
        List<User> users = mapper.userListByLimit(0, 2);
        for (User user : users) {
            System.out.println(user.toString());
        }
    }

Rowbounds

userMapper.java

public interface userMapper {
    //使用Rowbounds
    public List<User> userListByRowbounds(RowBounds rowBounds);
}

userMapper.xml

    <select id="userListByRowbounds" resultType="user">
        select * from user;
    </select>

测试:

    @Test
    public void userListByRowbounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        userMapper mapper = sqlSession.getMapper(userMapper.class);
        List<User> users = mapper.userListByRowbounds(new RowBounds(0, 2));
        for (User user : users) {
            System.out.println(user.toString());
        }
    }

区别

limitRowbounds二者区别就是解决问题的方式不同,limit是从SQL语句上解决问题,Rowbounds是从Java层面解决问题。
在实际开发中不建议使用Rowbounds来解决分页问题,原因是Rowbounds是将全部数据查询下来后,再根据所填的数据来进行分页,在大数据量的情况下这是十分影响效率的。

总结

  1. 结果集映射要求resultMap要和中的id属性一样
  2. 结果集映射主要解决的是当前查询语句所查询出来的表的列名属性名不一致的问题,并非是数据库列名和属性名不一致的问题,这点要注意
  3. 日志的使用在mybatis阶段主要是用来查看SQL语句,以及SQL语句执行结果
  4. 分页主要有三种:limit、Rowbounds,PageHelper
  5. 不推荐使用Rowbounds,因为它是全表查询,大数据量的情况下效率低下
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值