0
点赞
收藏
分享

微信扫一扫

Mybatis打印SQL配置

一、Log4j2

1、引入 Log4j2 依赖

<!-- log4j2依赖 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>

<!-- org.apache.ibatis.session.Configuration 会用上 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

2、添加 Log4j2.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>
    </Appenders>

    <Loggers>
        <!-- 打印SQL核心配置:将业务dao接口填写进去,并用控制台输出即可。"Console"为上面定义的 -->
        <logger name="com.example.mapper" level="DEBUG" additivity="false">
            <appender-ref ref="Console"/>
        </logger>

        <Root level="info">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

3、实体类

package com.example.entity;

import java.io.Serializable;

public class User implements Serializable {

    private Integer id;

    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

4、Mapper

package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

    @Select("select id, name from t_user")
    List<User> selectAllUsers();
}

5、Service

package com.example.service.impl;

import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> selectAllUsers() {
        return userMapper.selectAllUsers();
    }
}

6、配置类

package com.example.log4j.config;

import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("123456");
        return driverManagerDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 核心代码 configuration.setLogImpl(Log4j2Impl.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(Log4j2Impl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSource());
        return sqlSessionFactoryBean;
    }
}

7、测试类

package com.example.test;

import com.example.config.AppConfiguration;
import com.example.pojo.UserPojo;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfiguration.class);
        applicationContext.refresh();
        UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
        List<UserPojo> userPojoList = userServiceImpl.selectAllUserList();
        userPojoList.forEach(System.out::println);
    }
}

8、扩展

Log4j2第二种配置方式:
	log4j2.xml + org.apache.ibatis.logging.LogFactory.useLog4J2Logging();

1、引入 mybatis 依赖
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>

2、需要一个log4j2.xml,下面为打印SQL的标签
    <logger name="com.example.mapper" level="DEBUG" additivity="false">
    	<appender-ref ref="Console"/>
    </logger>
    
3、在Spring容器初始化前设置一个日志对象,内部会自动将该对象赋值给全局变量 logConstructor
    代码示例:
		org.apache.ibatis.logging.LogFactory.useLog4J2Logging();
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfiguration.class);
        applicationContext.refresh();


二、Log4j

1、引入 Log4j 依赖

<!-- Log4j -->
<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>

<!-- 搭建环境需要的依赖(偷个懒,用的SpringBoot的依赖,可能会有冲突) -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
  <version>2.7.15</version>
</dependency>
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.2.2</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.31</version>
</dependency>

2、添加 log4j.properties 文件

log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n
# 可打印出具体的结果,如下
log4j.logger.com.example.mapper=TRACE




# 具体日志打印内容如下:
# [DEBUG] 2024-02-29 22:49:19,942(67) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): Creating a new SqlSession  
# [DEBUG] 2024-02-29 22:49:19,947(72) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4189d70b] was not registered for synchronization because synchronization is not active  
# 22:49:19.953 [main] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
# 22:49:19.953 [main] DEBUG org.springframework.jdbc.datasource.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://192.168.0.118:3306/test]
# [DEBUG] 2024-02-29 22:49:20,684(809) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@45792847] will not be managed by Spring  
# [DEBUG] 2024-02-29 22:49:20,687(812) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): ==>  Preparing: select id, name from t_user  
# [DEBUG] 2024-02-29 22:49:20,702(827) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): ==> Parameters:   
# [TRACE] 2024-02-29 22:49:20,713(838) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace(BaseJdbcLogger.java:143): <==    Columns: id, name  
# [TRACE] 2024-02-29 22:49:20,713(838) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace(BaseJdbcLogger.java:143): <==        Row: 1, 张三  
# [DEBUG] 2024-02-29 22:49:20,718(843) --> [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:137): <==      Total: 1  
# [DEBUG] 2024-02-29 22:49:20,718(843) --> [main] org.mybatis.logging.Logger.debug(Logger.java:49): Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4189d70b] 

3、实体类

package com.example.entity;

import java.io.Serializable;

public class User implements Serializable {

    private Integer id;

    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

4、Mapper

package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

    @Select("select id, name from t_user")
    List<User> selectAllUsers();
}

5、Service

package com.example.service.impl;

import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> selectAllUsers() {
        return userMapper.selectAllUsers();
    }
}

6、配置类

package com.example.config;

import org.apache.ibatis.logging.log4j.Log4jImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("123456");
        return driverManagerDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 核心代码 configuration.setLogImpl(Log4jImpl.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(Log4jImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSource());
        return sqlSessionFactoryBean;
    }
}

7、测试类

package com.example.test;

import com.example.config.AppConfiguration;
import com.example.entity.User;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfiguration.class);
        applicationContext.refresh();
        UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
        List<User> users = userServiceImpl.selectAllUsers();
        users.forEach(System.out::println);
    }
}

8、扩展

Log4j第二种配置方式与log4j2的第二种方式一致:
	log4j.properties + org.apache.ibatis.logging.LogFactory.useLog4JLogging();


代码示例:
  org.apache.ibatis.logging.LogFactory.useLog4JLogging();
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  applicationContext.register(AppConfiguration.class);
  applicationContext.refresh();


三、自定义 Log 对象,实现 org.apache.ibatis.logging.Log 接口

1、自定义一个 Log 对象,实现 org.apache.ibatis.logging.Log 接口,重写接口下的方法

package com.example.log4j;

import org.apache.ibatis.logging.Log;

import java.util.logging.Logger;

public class CustomLog implements Log {

    // 这里需要加上一个这种类型的构造器
    // 不加直接报错:
    //    NoSuchMethodExcetpion: com.example.log.CustomLog.<init>(java.lang.String)
    public CustomLog(String msg) {

    }

    /* 	
        这里使用的 JUL 方式测试打印 mybatis 的 SQL ,因为 Mybatis 中会判断,日志对象是 Debug 级
        别时才会打印 Mybatis 的 SQL,而 JUL 级别默认是 info 及以上的级别,所以
        默认是打印不出 Mybatis 的 SQL 的,但我们自定义的可以稍微改动,使其用 JUL 打印 SQL。
    */
    Logger logger = Logger.getLogger("jul");

    // 源码中有许多判断日志级别的代码,为 debug 级别才打印,xxx.isDebugEnabled(),就是下面这个方法
    @Override
    public boolean isDebugEnabled() {
        return true;
    }

    @Override
    public boolean isTraceEnabled() {
        return false;
    }

    @Override
    public void error(String s, Throwable e) {

    }

    @Override
    public void error(String s) {

    }

    // 如果是 debug 级别,外部就会调用 log.debug(s),就是执行下面这个方法
    @Override
    public void debug(String s) {
        logger.info(s);
    }

    @Override
    public void trace(String s) {

    }

    @Override
    public void warn(String s) {

    }
}

2、配置类

package com.example.log4j.config;

import org.apache.ibatis.logging.log4j2.Log4j2Impl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.example")
@MapperScan("com.example.mapper")
public class AppConfiguration {

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        driverManagerDataSource.setUrl("jdbc:mysql://192.168.0.118:3306/test");
        driverManagerDataSource.setUsername("root");
        driverManagerDataSource.setPassword("123456");
        return driverManagerDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        // 核心代码 configuration.setLogImpl(CustomLog.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // 这句代码底层就是调用 使用自定义Log对象 方法
        configuration.setLogImpl(CustomLog.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSource());
        return sqlSessionFactoryBean;
    }
}

3、测试类

package com.example.test;

import com.example.config.AppConfiguration;
import com.example.entity.User;
import com.example.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfiguration.class);
        applicationContext.refresh();
        UserServiceImpl userServiceImpl = applicationContext.getBean(UserServiceImpl.class);
        // 调用下面方法会打印SQL
        List<User> users = userServiceImpl.selectAllUsers();
        users.forEach(System.out::println);
    }
}


四、配置文件说明

1、log4j2.xml

    // 打印日志核心配置
    <logger name="com.example.mapper" level="DEBUG" additivity="false">
        <appender-ref ref="Console"/>
    </logger>
    
    
2、log4j.properties
    
    // 打印日志核心配置
    log4j.logger.com.example.mapper.UserMapper=DEBUG

    
    
    
/*
	以上两个配置文件可以搭配setLogImpl方法使用,Mybatis的打印SQL功能也会生效
	setLogImpl两种方式:
		①代码方式:
			configuration.setLogImpl(Log4j2Impl.class);
			
		②mybatis-config.xml方式:
			<configuration>
              <settings>
                ...
                <setting name="logImpl" value="LOG4J"/>
                ...
              </settings>
            </configuration>
    
	这两种方式底层其实是调用了 LogFactory.useCustomLogging(this.logImpl); 方法,将传入的Log对象赋值给 全局的Log对象 logConstructor
		
	若只有 setLogImpl 而没有 ① 和 ②,则在 org.apache.ibatis.executor.BaseExecutor 类中 getConnection(Log statementLog) 方法中无法通过 statementLog.isDebugEnabled() 校验,从而无法产生代理对象 org.apache.ibatis.logging.ConnectionLogger ,也就不能打印方法执行的SQL。
	没通过 statementLog.isDebugEnabled() 校验时,Connection 对象为 JDBC4Connection,不打印SQL。
	
	而自定义的 CustomLog 对象之所以能够打印 SQL 正是因为重写了 Log 接口中的 isDebugEnabled() 方法并始终返回 true,所以他也能够通过 statementLog.isDebugEnabled() 校验,并产生代理对象 org.apache.ibatis.logging.ConnectionLogger,从而实现打印方法执行的SQL功能。
	
	所以,执行mapper接口方法时,打印出其SQL语句日志的条件为:
		需要保证当前日志对象的 isDebugEnabled() 为 true 。
	
	调试入口:
		org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor
			Object result = method.invoke(sqlSession, args);


举报

相关推荐

0 条评论