原创 夏壹 夏壹分享 2024年07月18日 08:30
在Spring Boot项目中,经常需要打印SQL语句及其参数,以便于调试和优化数据库操作。
本文将介绍几种在Spring Boot项目中实现SQL日志打印的方法。
-
使用MyBatis-Plus配置日志打印
案例背景:
在Spring Boot项目中,如果使用了MyBatis-Plus框架,可以通过简单的配置来实现SQL日志的打印,便于开发和调试。
配置步骤:
-
修改application.properties或application.yml文件:
在配置文件中添加以下配置来开启MyBatis-Plus的SQL日志打印功能。
# application.properties 示例
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
或者在application.yml
中配置:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
效果展示:
配置完成后,当应用执行数据库操作时,MyBatis-Plus会自动将执行的SQL语句及其参数打印到控制台。例如:
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@xxx] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@xxx] will not be managed by Spring
==> Preparing: SELECT t3.user_id, t3.user_name, t2.role_id, t2.role_name FROM my_user_role_rel t1 LEFT JOIN my_role t2 ON t1.role_id = t2.role_id LEFT JOIN my_user t3 ON t1.user_id = t3.user_id WHERE t1.user_id = ? AND t2.role_id = ?
==> Parameters: 1(Long), 1(Long)
<== Columns: user_id, user_name, role_id, role_name
<== Row: 1, 用户1, 1, 超级管理员
<== Row: 1, 用户1, 2, 游客
<== Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@xxx]
优势:
-
配置简单,无需编写额外代码。
-
适用于大多数基于MyBatis-Plus的Spring Boot项目。
2. 整合p6spy框架进行SQL日志跟踪
案例背景:
p6spy是一个开源的数据库操作监控工具,可以拦截并记录应用程序发送到数据库的SQL语句及其执行时间等信息。
配置步骤:
-
添加p6spy依赖:
在项目的pom.xml
文件中添加p6spy的Maven依赖。
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>最新版本号</version>
</dependency>
修改数据源配置:
在application.properties
或application.yml
文件中修改数据源配置,使用p6spy的Driver。
# application.properties 示例
spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/yourdatabase?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
配置spy.properties:
在src/main/resources
目录下创建spy.properties
文件,进行p6spy的详细配置,如日志格式、日志级别等。
# spy.properties 示例
appender=com.p6spy.engine.spy.appender.StdoutLogger
logMessageFormat=custom
customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|%(sql)
效果展示:
配置完成后,p6spy会自动拦截并记录所有数据库操作,将SQL语句及其执行时间等信息打印到控制台或指定的日志文件中。
|2023-04-01 12:34:56|0ms|0|statement|select * from users where id = ?|select * from users where id = 1
|2023-04-01 12:34:56|10ms|0|statement|insert into logs (message, timestamp) values (?, ?)|insert into logs (message, timestamp) values ('User 1 logged in', '2023-04-01T12:34:56Z')
|2023-04-01 12:35:00|2ms|0|statement|update users set status = ? where id = ?|update users set status = 'active' where id = 1
优势:
-
功能强大,支持详细的SQL日志跟踪。
-
可配置性强,支持多种日志格式和输出方式
3. 使用MyBatis拦截器实现系统日志记录
MyBatis提供了强大的拦截器功能,允许我们在SQL语句执行的不同阶段插入自定义的逻辑。通过实现MyBatis的Interceptor
接口,我们可以轻松地记录SQL语句及其参数。
步骤 1: 创建MyBatis拦截器
首先,我们需要创建一个类来实现Interceptor
接口。在这个类中,我们将编写拦截SQL语句的逻辑,并在执行前后记录日志。
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
@Intercepts({@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)})
public class SqlLoggingInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) Plugin.getTarget(invocation.getTarget());
// 获取SQL语句
String sql = statementHandler.getBoundSql().getSql();
// 获取SQL参数(可能需要根据实际情况进行解析)
Object parameterObject = statementHandler.getBoundSql().getParameterObject();
// 这里可以添加日志记录逻辑
System.out.println("Executing SQL: " + sql);
// 注意:直接打印参数对象可能不是很有用,因为它可能是一个复杂的对象
// 在实际应用中,你可能需要解析这个对象并打印出具体的参数值
// 继续执行原有的逻辑
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 可以在这里设置拦截器的属性
}
}
复制代码
步骤 2: 配置MyBatis拦截器
接下来,你需要在MyBatis的配置文件(如mybatis-config.xml
)或Spring Boot的配置中注册这个拦截器。
对于Spring Boot项目,你通常可以通过配置类来注册MyBatis拦截器:
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisConfig {
@Bean
public SqlLoggingInterceptor sqlLoggingInterceptor() {
return new SqlLoggingInterceptor();
}
@Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer(SqlLoggingInterceptor sqlLoggingInterceptor) {
return configuration -> configuration.addInterceptor(sqlLoggingInterceptor);
}
}
注意事项
-
拦截器可能会稍微降低应用程序的性能,因为它在每次数据库操作之前和之后都执行了额外的代码。
-
在生产环境中,你可能希望关闭详细的SQL日志记录,以避免敏感信息泄露或日志文件过大。
-
解析复杂的参数对象可能需要编写额外的代码,并且可能会引入错误。确保你的参数解析逻辑是健壮的,并且不会引入新的性能问题。
4. 结合Logback和application.properties
如果你的项目使用了Spring Boot默认的日志框架Logback,并且想要通过application.properties
文件结合Logback的配置来打印SQL日志,你可以通过修改logback-spring.xml
文件(或logback.xml
,取决于你的项目结构)来实现。
但是,通常情况下,对于SQL日志的打印,我们更多地是通过application.properties
或application.yml
中的日志级别配置来控制,而不是直接在Logback配置文件中指定。不过,为了完整性,这里说明一下Logback配置文件的潜在用途。
在logback-spring.xml
中,你可以为特定的日志记录器(logger)设置级别,例如:
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
然而,请注意,在实际项目中,更常见的做法是直接通过application.properties
或application.yml
中的配置来控制日志级别,因为这样做更加简便且易于管理。