【Log4j2】开发环境配置日志策略打印完整MyBatis语句到文件

26 篇文章 0 订阅
18 篇文章 0 订阅

前言

公司项目用的 Spring Boot,选用的是 Log4j2 作为日志实现,本地开发的时候没有把sql语句打印到文件中,并且控制台输出的sql需要自己拼接,看了log4j2官网后整理了个日志文件demo实现自己的需求。Logback作为 Spring Boot自动装配的默认实现,所以选用Log4j2 记得要排除掉默认依赖。

依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</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>5.1.25</version>
		</dependency>

application.yml

这里习惯引用外部的配置文件

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/james?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

mybatis:
  config-location: classpath:mybatis.xml 
  mapper-locations: classpath:mapper/*.xml 

logging:
  config: classpath:log4j2.xml

mybatis.xml

这个文件用于打印完整的sql语句,遵循mybatis的规范(接口),对应的Java代码是摘录网上的。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.james.usinglog.MybatisInterceptor"/>
    </plugins>
</configuration>
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Intercepts({
        @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
        @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class }) })
public class MybatisInterceptor implements Interceptor {

    Logger LOGGER = LoggerFactory.getLogger(MybatisInterceptor.class);

    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        Object parameter = null;
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        String sqlId = mappedStatement.getId();
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        Configuration configuration = mappedStatement.getConfiguration();
        Object returnValue = null;
        long start = System.currentTimeMillis();
        returnValue = invocation.proceed();
        long end = System.currentTimeMillis();
        long time = (end - start);
        if (time > 1) {
            String sql = showSql(configuration, boundSql);
            LOGGER.warn(">> {}", sql);
        }
        return returnValue;
    }
 
    private static String getParameterValue(Object obj) {
        String value = null;
        if (obj instanceof String) {
            value = "'" + obj + "'";
        } else if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            value = "'" + formatter.format(new Date()) + "'";
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "";
            }
 
        }
        return value;
    }
 
    public static String showSql(Configuration configuration, BoundSql boundSql) {
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
        if (parameterMappings.size() > 0 && parameterObject != null) {
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));
 
            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    }
                }
            }
        }
        return sql;
    }
 
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
}

log4j2.xml

为指定文件/包定制日志级别

开发阶段不想看到满屏幕的日志,可以把日志级别控制到 info ,对于自己想要详细打日志的类,则另外指定;
借用的是 官网的继承体系 ,跟logback很像 。

  • 全局日志级别
        <Root level="info">
            <AppenderRef ref="MyFile"/>
        </Root>
  • 只看自己项目内的debug日志
        <Logger name="com.james" level="debug" additivity="false">
            <AppenderRef ref="MyFile"/>
        </Logger>
  • 让Mybatis打印的sql语句声明为 warn
    这里是借鉴了阿里把用户输入请求打印成warn方便检索。同时可以在idea配置warn日志高亮。
		<Logger name="com.james.usinglog.MybatisInterceptor" level="warn" additivity="false">
            <AppenderRef ref="MyFile"/>
        </Logger>

RollingFile 的 pattern 有两重含义

  1. 确认文件文件名格式,包括路径名
  2. 结合 TimeBasedTriggeringPolicy 使用时候, 形如 %d{yyyy-MM-dd_HH-mm} 的模式告知了最小的计量单位是分钟
    • <TimeBasedTriggeringPolicy interval="5"/>
      一个文件至多保持5分钟的日志 (JVM一直在运行)
      • 35分钟运行了一次测试用例,36分钟运行了一次测试用例。如果运行完测试用例JVM都退出了,会生成两份日志文件。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
    <Appenders>
        <RollingFile name="MyFile" filePattern="logs/$${date:yyyy-MM}/app-[%d{yyyy-MM-dd_HH-mm}].log">
            <PatternLayout>
                <Pattern>
                    [%d{MM-dd HH:mm:ss}]-[%p][%tid][%logger{0}:%line]  %m%n
                </Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy interval="5"/>
                <SizeBasedTriggeringPolicy size="250 MB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Logger name="com.james" level="debug" additivity="false">
            <AppenderRef ref="MyFile"/>
        </Logger>
        <Logger name="com.james.usinglog.MybatisInterceptor" level="warn" additivity="false">
            <AppenderRef ref="MyFile"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="MyFile"/>
        </Root>
    </Loggers>
</Configuration>

后记

本地开发环境的日志配置很灵活,按自己的需求来,好方便排除问题即可。本文积累了下MyBatis完整日志打印的配置和用法和RollingFile 的表达式语义。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 你可以在 MyBatis 的配置文件中开启日志,然后在日志中输出完整的 SQL 语句及其参数。具体步骤如下: 1. 在 MyBatis 的配置文件(通常是 `mybatis-config.xml`)中添加以下配置: ```xml <configuration> <!-- 其他配置 --> <settings> <!-- 开启 MyBatis 打印 SQL 日志 --> <setting name="logImpl" value="LOG4J2" /> <setting name="logLevel" value="TRACE" /> </settings> </configuration> ``` 2. 在日志输出中查看完整的 SQL 语句及其参数。 如果使用的是 Log4j2 日志框架,可以在日志配置文件中添加 MyBatis日志输出器,例如: ```xml <Configuration status="WARN"> <!-- 其他配置 --> <Loggers> <!-- 开启 MyBatis 的 SQL 日志输出 --> <Logger name="org.mybatis" level="TRACE" additivity="false"> <AppenderRef ref="Console" /> </Logger> <!-- 其他日志配置 --> </Loggers> </Configuration> ``` 这样就可以在控制台或日志文件中查看 MyBatis 输出的完整 SQL 语句及其参数了。注意,开启完整 SQL 日志会输出所有的 SQL 语句及其参数,包括一些系统自动生成的查询,同时也会输出敏感信息,如密码等,因此在生产环境中应该关闭该配置。 ### 回答2: MyBatis是一个开源的Java持久层框架,它与数据库之间的交互是通过SQL语句来实现的。在使用MyBatis进行数据库操作时,有时我们希望能够打印完整的SQL语句,以便于调试和优化。 在MyBatis中,可以通过配置来开启打印完整SQL语句的功能。具体的配置如下: 1. 在MyBatis的配置文件(通常是`mybatis-config.xml`)中,添加如下配置: ```xml <configuration> ... <settings> ... <setting name="logImpl" value="STDOUT_LOGGING"/> ... </settings> ... </configuration> ``` 2. 在数据源的配置中,设置`driver`属性为`org.apache.ibatis.logging.stdout.StdOutImpl`。 ``` <dataSource type="POOLED"> ... <property name="driver" value="org.apache.ibatis.logging.stdout.StdOutImpl"/> ... </dataSource> ``` 通过以上配置,MyBatis会将完整的SQL语句打印到标准输出流(console)中。 需要注意的是,打印完整的SQL语句会对性能有一定的影响,因此在生产环境中不建议开启此功能。一般情况下,我们可以在开发调试阶段使用,以便于定位问题和优化SQL语句。 除了通过上述配置方式,我们还可以通过其他方法来打印完整的SQL语句,比如使用日志框架或在代码中手动打印。但值得一提的是,MyBatis提供的配置方式更为方便和统一,推荐使用。 ### 回答3: 可以通过配置文件来实现在MyBatis打印完整的sql语句。 在配置文件中,可以设置MyBatis日志级别为debug。在日志级别设置为debug后,MyBatis打印出执行的sql语句。 具体实现步骤如下: 1. 打开mybatis的配置文件(一般为mybatis-config.xml)。 2. 在配置文件中找到<configuration>标签,添加一个<settings>标签,用于设置MyBatis的各项配置。 3. 在<settings>标签中添加<setting>标签,并设置name为logImpl,value为STDOUT_LOG_IMPL(即使用控制台输出日志)或者其他日志所支持的输出方式。 4. 在<settings>标签中添加<setting>标签,并设置name为logLevel,value为DEBUG(即设置日志级别为debug)。 5. 保存并关闭配置文件。 配置完成后,重新运行程序,MyBatis会将执行的sql语句输出到控制台。通过这种方法,我们可以方便地查看MyBatis执行的完整sql语句,以便于调试和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值