在开发过程中,我们经常需要查看正在执行的SQL语句以及相应的参数值,以便于调试和优化程序。本篇将介绍如何使用Spring Boot和JPA来输出打印SQL语句和传入的参数,并对日志输出进行美化。
配置日志输出
首先,我们需要在application.properties
或application.yml
中进行日志配置。我们将使用logback作为日志框架,并设置相应的日志级别。
spring:
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
上述配置中,spring.jpa.show-sql
设置为true
表示允许打印SQL语句,spring.jpa.properties.hibernate.format_sql
设置为true
表示在打印SQL语句时进行格式化。
创建日志输出类
接下来,我们创建一个日志输出类,用于输出打印SQL语句和传入的参数。我们使用@Component
注解将该类注入到Spring容器中。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import java.util.Arrays;
@Component
public class JpaSqlLogInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(JpaSqlLogInterceptor.class);
public void log(String sql, Object[] args) {
LOGGER.info("Executing SQL: {}", sql);
LOGGER.info("Params: {}", Arrays.toString(args));
}
public void logQuery(String sql, Object[] args) {
LOGGER.info("Query: {}", sql);
LOGGER.info("Params: {}", Arrays.toString(args));
}
public void logTime(StopWatch stopWatch) {
LOGGER.info("Execution Time: {} ms", stopWatch.getTotalTimeMillis());
}
}
上述代码中,我们使用log
方法输出执行的SQL语句和参数,使用logQuery
方法输出查询的SQL语句和参数,使用logTime
方法输出执行时间。StopWatch
用于计算执行时间。
创建日志输出拦截器
接下来,我们创建一个日志输出拦截器来拦截JPA执行的SQL语句。我们需要实现QueryInterceptor
接口的beforeQuery
和afterQuery
方法。
import org.springframework.util.StopWatch;
import javax.persistence.Query;
public class JpaSqlLogQueryInterceptor implements QueryInterceptor {
private final JpaSqlLogInterceptor sqlLogInterceptor;
public JpaSqlLogQueryInterceptor(JpaSqlLogInterceptor sqlLogInterceptor) {
this.sqlLogInterceptor = sqlLogInterceptor;
}
@Override
public void beforeQuery(Query query, StopWatch stopWatch) {
String sql = query.unwrap(org.hibernate.query.Query.class).getQueryString();
Object[] args = query.getParameters().toArray();
sqlLogInterceptor.logQuery(sql, args);
}
@Override
public void afterQuery(Query query, StopWatch stopWatch) {
sqlLogInterceptor.logTime(stopWatch);
}
}
上述代码中,我们通过query
对象获取SQL语句和参数,并调用sqlLogInterceptor
的logQuery
和logTime
方法进行日志输出。
创建JPA配置类
接下来,我们创建一个JPA配置类,并将上面创建的拦截器添加到JPA的Provider中。
import org.hibernate.jpa.QueryInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
private final JpaSqlLogInterceptor sqlLogInterceptor;
@Autowired
public JpaConfig(JpaSqlLogInterceptor sqlLogInterceptor) {
this.sqlLogInterceptor = sqlLogInterceptor;
}
@Bean
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(JpaVendorAdapter jpaVendorAdapter) {
return properties -> {
properties.put(org.hibernate.cfg.Environment.INTERCEPTOR, (QueryInterceptor) (query, stopWatch) -> {
JpaSqlLogQueryInterceptor interceptor = new JpaSqlLogQueryInterceptor(sqlLogInterceptor);
interceptor.beforeQuery(query, stopWatch);
});
};
}
}
上述代码中,我们通过HibernatePropertiesCustomizer
自定义Hibernate的属性。将自定义的拦截器添加到INTERCEPTOR
属性中。
测试输出
最后,我们可以测试程序并查看日志输出结果。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.util.StopWatch;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
@SpringBootApplication
public class Application implements CommandLineRunner {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private JpaSqlLogInterceptor sqlLogInterceptor;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
String queryString = "SELECT * FROM users WHERE age > :age";
Query query = entityManager.createNativeQuery(queryString);
query.setParameter("age", 20);
StopWatch stopWatch = new StopWatch();
stopWatch.start();
query.getResultList();
stopWatch.stop();
sqlLogInterceptor.logQuery(queryString, query.getParameters().toArray());
sqlLogInterceptor.logTime(stopWatch);
}
}
我们通过创建一个NativeQuery
对象,并执行查询操作。在run
方法中调用sqlLogInterceptor
的相应方法输出日志。
查看日志输出,我们可以看到打印了执行的SQL语句和参数,以及执行时间。
以上就是使用Spring Boot和JPA输出打印SQL语句和传入参数的高阶篇。通过配置日志输出和创建日志输出拦截器,可以方便地查看SQL语句和参数,帮助我们进行调试和优化。
希望本篇对你有所帮助,谢谢阅读!
本文来自极简博客,作者:星辰守望者,转载请注明原文链接:Spring Boot JPA日志输出打印SQL语句和传入的参数 - 高阶篇