配置 mybatis 打印出执行的 sql 及返回的结果集

介绍了如果配置 mybatis 以打印出执行的 sql 及返回的结果集, 从而方便开发阶段的调试

目录
[隐藏]

在开发过程中, 经常会遇到想要看到应用所执行的 sql 这样的需求.

比如你写了一个查询的功能, 但查询出来的结果与你预期的不符合, 你想搞清楚到底哪里出了问题, 你自然需要看看所执行的 sql 语句, 必要的话甚至还要亲自拷贝到数据库里去查查.

自然, 这就要求应用要能把执行的 sql 输出出来. 以常用的 mybatis 框架为例, 来看一个最终的效果:

14:48 ==>  Preparing: select * from user where id = ? 
14:48 ==> Parameters: 1(Integer)
14:48 <==      Total: 1

另注: 这里的日志布局我启用了一种极简的风格, 只有"分钟:秒数", 具体见 配置简化开发阶段日志输出布局 的介绍.

那么, 在 mybatis 里, 这个要怎么做到呢?

配置 sql 输出

具体来说, 是要增加一个日志级别的配置, 将 dao(或 mapper) 包级别调整到 DEBUG.

示例:

# log sql statement
logging.level.net.xiaogd.sample.mybatis.dao=DEBUG

注: 上述配置建议放在你的本地开发环境配置文件中, 通常为 application-dev.properties, 关于 spring-boot 的 分环境配置profile 机制, 如不熟悉请自行查阅网络了解.

对应工程代码包结构如下:

工程包结构

注: 我的代码结构下, mybatis 相关的类放到了 dao 这个包下, 你的如果不是这样, 可以根据自己的情况加以调整.

在上述配置下, 执行以下测试:

package net.xiaogd.sample.mybatis.dao.user;

import lombok.extern.slf4j.Slf4j;
import net.xiaogd.sample.mybatis.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@Slf4j
@RunWith(SpringRunner.class)
@MybatisTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class SimpleTest {

    @Autowired
    private UserDao userDao;

    @Test
    public void testGetUserById() {
        User user = userDao.findUserById(1);
        log.info("user find id: {}", user.getId());
    }
}

相应的 dao 接口:

package net.xiaogd.sample.mybatis.dao.user;

import net.xiaogd.sample.mybatis.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserDao {

    @Select("select * from user where id = #{id}")
    User findUserById(int id);
}

相应的 sql 语句, 参数值及查询的总数都会打印出来:

14:48 ==>  Preparing: select * from user where id = ? 
14:48 ==> Parameters: 1(Integer)
14:48 <==      Total: 1

输出结果集

如果想进一步输出结果集, 则可以进一步把日志级别提升到 TRACE. 如下:

# log sql statement and result set
logging.level.net.xiaogd.sample.mybatis.dao=TRACE

警告: 可能导致大量的日志输出, 非必要情况下不要启用, 且仅可以在本地开发环境调试情况下启用!

对于下述的数据表:

表数据

最终的输出如下:

17:36 ==>  Preparing: select * from user 
17:36 ==> Parameters: 
17:36 <==    Columns: id, username, password, nick_name
17:36 <==        Row: 1, admin, 123456, 管理员
17:36 <==        Row: 2, root, root, 根用户
17:36 <==      Total: 2

可以看到字段及每行的值都被打印出来了.

遗留问题

当然了, 上述在输出 sql 语句时还有一个问题, 就是在有参数的情况下, 这个还不是最终的 sql, 而是类似于 jdbc 中的那种 prepare statement:

select * from user where id = ? 

可以看到参数的值是用一个问号占位符代替的, 真正的参数值输出到了另一行.

如果要真的拷贝到数据库查看工具里执行, 比如 navicat 或者 mysql workbench 抑或是最简单的 mysql console 中, 我们还是得自行替换及拼凑最终的 sql.

虽然多数情况下这也不是特别麻烦, 但在特别多参数的情况下, 如果你发现执行结果不对, 用眼睛看输出的参数值似乎也没有问题, 自行去拼凑就有点麻烦了, 能否直接输出最终的 sql 呢? 也是有方式的, 我们将在下一篇再介绍这种方式.

参考文档

更多打印 sql 日志相关的配置, 请参考其官网: https://mybatis.org/mybatis-3/logging.html