Spring Boot JPA日志输出打印SQL语句和传入的参数 - 高阶篇

星辰守望者 2024-06-21 ⋅ 226 阅读

在开发过程中,我们经常需要查看正在执行的SQL语句以及相应的参数值,以便于调试和优化程序。本篇将介绍如何使用Spring Boot和JPA来输出打印SQL语句和传入的参数,并对日志输出进行美化。

配置日志输出

首先,我们需要在application.propertiesapplication.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接口的beforeQueryafterQuery方法。

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语句和参数,并调用sqlLogInterceptorlogQuerylogTime方法进行日志输出。

创建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语句和参数,帮助我们进行调试和优化。

希望本篇对你有所帮助,谢谢阅读!


全部评论: 0

    我有话说: