当前位置: 首页 > 知识库问答 >
问题:

使用Hibernate和Spring数据JPA激活SQL语句日志记录

聂涛
2023-03-14

我有一个使用Hibernate作为提供者的Spring数据JPA存储库。我想记录SQL语句,但我做不到。我尝试了各种解决方案:

  • 在我的HibernateJPavendorAdapter中将showSql设置为true
  • 将log4j.logger.org.hibernate.sql=debug添加到我的log4j.properties文件(值得一提的是,log4j.logger.org.hibernate=info确实添加了一些日志信息,但log4j.logger.org.hibernate.sql=debug没有添加)

下面是我的类和配置文件:

DatabaseConfiguration.java

/**
 * Database configuration
 *
 * @author dupirefr
 */
@Configuration
@Import({BaseConfiguration.class, DatabaseProperties.class})
@EnableJpaRepositories(basePackages = DatabaseConfiguration.REPOSITORIES_PACKAGE)
public class DatabaseConfiguration {

    /*
     * Constants
     */
    public static final String MODEL_PACKAGE = "be.dupirefr.examples.spring.batch.simple.model";
    public static final String REPOSITORIES_PACKAGE = "be.dupirefr.examples.spring.batch.simple.repositories";

    /*
     * Beans
     */
    @Bean
    public DataSource dataSource(DatabaseProperties properties) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(properties.url);
        dataSource.setUsername(properties.username);
        dataSource.setPassword(properties.password);
        dataSource.setDriverClassName(properties.driverClassName);

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPackagesToScan(MODEL_PACKAGE);
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        return entityManagerFactoryBean;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

数据库.属性

# Data source
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=admin
spring.datasource.password=admin
spring.datasource.driver-class-name=org.h2.Driver

DatabaseProperties.java

/**
 * Database properties
 *
 * @author dupirefr
 */
@Configuration
@PropertySource("classpath:be/dupirefr/examples/spring/batch/simple/config/database/database.properties")
public class DatabaseProperties {

    /*
     * Fields
     */
    @Value("${spring.datasource.url}")
    public String url;

    @Value("${spring.datasource.username}")
    public String username;

    @Value("${spring.datasource.password}")
    public String password;

    @Value("${spring.datasource.driver-class-name}")
    public String driverClassName;

}
/**
 * {@link Employer}'s repository
 *
 * @author dupirefr
 */
@Repository
public interface EmployerRepository extends JpaRepository<Employer, Long> {

}
/**
 * {@link EmployerRepository}'s integration test
 *
 * @author dupirefr
 */
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DatabaseConfiguration.class)
@Transactional
public class EmployerRepositoryIT {

    /*
     * Constants
     */
    public static final Employer GOOGLE = new Employer(1L, "Google");
    public static final Employer MICROSOFT = new Employer(2L, "Microsoft");
    public static final Employer APPLE = new Employer(3L, "Apple");

    /*
     * Fields
     */
    @Autowired
    private EmployerRepository repository;

    @Autowired
    private EntityManager entityManager;

    /*
     * Setups
     */
    @Before
    public void setUp() {
        entityManager.persist(GOOGLE);
        entityManager.persist(MICROSOFT);
    }

    /*
     * Tests
     */
    @Test
    public void findById_Exists() {
        assertEquals(GOOGLE, repository.findById(GOOGLE.getId()).get());
        assertEquals(MICROSOFT, repository.findById(MICROSOFT.getId()).get());
    }

    @Test
    public void findById_NotExists() {
        assertFalse(repository.findById(Long.MAX_VALUE).isPresent());
    }

    @Test
    public void findAll() {
        assertEquals(Arrays.asList(GOOGLE, MICROSOFT), repository.findAll());
    }

    @Test
    public void save() {
        repository.save(APPLE);
        assertEquals(APPLE, entityManager.find(Employer.class, APPLE.getId()));
    }

    @Test
    public void delete() {
        repository.delete(MICROSOFT);
        assertNull(entityManager.find(Employer.class, MICROSOFT.getId()));
    }

}
# Appenders
## Console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

# Loggers
## Root
log4j.rootLogger=INFO, stdout

## Hibernate
### Generic
log4j.logger.org.hibernate=INFO
### SQL statements
log4j.logger.org.hibernate.SQL=DEBUG

编辑:我尝试了评论中提出的两种解决方案,但都不奏效。我还尝试更改我正在使用的数据库(H2 for HSQL),或者指定Hibernate方言,但都不起作用。事实上,在使用Spring时,某些数据库会自动找到Hibernate方言。

编辑2:我尝试将rootLogger的日志级别更改为trace。我还试图明确地为追加器指定一个阈值。最后,我尝试用showSql=true添加JpaProperties,但没有一个能起到作用。我认为有一件事情是很明显的,我错过了去解开完整的局面:-/

编辑3:像下面的测试那样直接调用记录器起作用了。我开始怀疑是否有一个错别字或者什么东西阻止了Hibernate使用记录器。

@Test
public void delete() {
    LoggerFactory.getLogger("org.hibernate.SQL").debug("delete()");
    repository.delete(MICROSOFT);
    assertNull(entityManager.find(Employer.class, MICROSOFT.getId()));
}
10:33:45,158  INFO DefaultTestContextBootstrapper:257 - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
10:33:45,183  INFO DefaultTestContextBootstrapper:206 - Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
10:33:45,185  INFO DefaultTestContextBootstrapper:184 - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@1f28c152, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@7d907bac, org.springframework.test.context.support.DirtiesContextTestExecutionListener@7791a895, org.springframework.test.context.transaction.TransactionalTestExecutionListener@3a5ed7a6, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@6325a3ee]10:33:45,376  INFO GenericApplicationContext:589 - Refreshing org.springframework.context.support.GenericApplicationContext@4493d195: startup date [Sun Jan 14 10:33:45 CET 2018]; root of context hierarchy
10:33:46,187  WARN ConfigurationClassEnhancer:353 - @Bean method BaseConfiguration.propertySourcesPlaceholderConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
10:33:46,448  INFO DriverManagerDataSource:133 - Loaded JDBC driver: org.h2.Driver
10:33:46,743  INFO LocalContainerEntityManagerFactoryBean:361 - Building JPA container EntityManagerFactory for persistence unit 'default'
10:33:46,798  INFO LogHelper:31 - HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
10:33:46,922  INFO Version:45 - HHH000412: Hibernate Core {5.2.12.Final}
10:33:46,924  INFO Environment:213 - HHH000206: hibernate.properties not found
10:33:46,979  INFO Version:66 - HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
10:33:47,318  INFO Dialect:157 - HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
10:33:48,472  INFO LocalContainerEntityManagerFactoryBean:393 - Initialized JPA EntityManagerFactory for persistence unit 'default'
10:33:49,422  INFO TransactionContext:105 - Began transaction (1) for test context [DefaultTestContext@2e3f79a2 testClass = EmployerRepositoryIT, testInstance = be.dupirefr.examples.spring.batch.simple.repositories.EmployerRepositoryIT@1460c81d, testMethod = delete@EmployerRepositoryIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@38b5f25 testClass = EmployerRepositoryIT, locations = '{}', classes = '{class be.dupirefr.examples.spring.batch.simple.config.database.DatabaseConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@5b22b970]; rollback [true]
10:33:49,468 DEBUG SQL:83 - delete()
10:33:49,512  INFO TransactionContext:137 - Rolled back transaction for test context [DefaultTestContext@2e3f79a2 testClass = EmployerRepositoryIT, testInstance = be.dupirefr.examples.spring.batch.simple.repositories.EmployerRepositoryIT@1460c81d, testMethod = delete@EmployerRepositoryIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@38b5f25 testClass = EmployerRepositoryIT, locations = '{}', classes = '{class be.dupirefr.examples.spring.batch.simple.config.database.DatabaseConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]].
10:33:49,516  INFO GenericApplicationContext:989 - Closing org.springframework.context.support.GenericApplicationContext@4493d195: startup date [Sun Jan 14 10:33:45 CET 2018]; root of context hierarchy
10:33:49,519  INFO LocalContainerEntityManagerFactoryBean:571 - Closing JPA EntityManagerFactory for persistence unit 'default'

编辑3:我终于弄明白发生了什么事。我注意到,对于失败的测试,日志中会发出SQL查询。通过对我的log4j属性进行一点调优,我看到它们来自hibernate logger,正如所预期的那样。

但成功的操作并不是发布日志。那是因为他们无法进入数据库。所有事情都发生在实体管理器中,因此不需要SQL。现在我知道我只是有一个问题与我的H2数据库,我需要解决。

共有1个答案

锺离卓
2023-03-14

既然看着你提供的代码似乎并不适合,我就试一下如何调试它的一些说明。

>

  • 保留我在第一个回答中给出的更改。

    确保您显示的属性文件实际控制了记录器配置。对于此更改,例如,输出格式,并检查它是否如预期的那样影响了输出。

  •  类似资料:
    • 我试图通过连接eclipse IDE中的Oracle数据库,使用JDBC程序启用日志。 我已经完成了这个SO post JDBC日志记录到文件,然后我创建了下面的java程序并从我的eclipse IDE运行它,但是我看不到JDBC驱动程序类生成的任何日志。 我的OracleLog中有以下内容。属性文件: 但是当我通过将放在类路径中运行我的程序时,我会得到异常: 如果我在类路径中有ojdbc6\u

    • 目前,我正在与 log4j2.7 springframework 4.3。5; 冬眠5.2。三, 我通过一个xml文件配置log4j 为此,我创建了一些appender,其中一个名为“General”。我需要的是,所有日志都必须转到该appender(包括springframework或hibernate生成的日志),并且后者都不会打印在控制台上(我仍然需要其他类中的其他日志) 我试着写这些日志:

    • 问题内容: 我有一个专门用于通过hibernate的持久层将数据持久保存在db中的类。 问题在于它不会持久保存数据。 堆栈是: 但我必须指出,它在其他课程中也能正常工作。 更新 : 当我印刷它给我的时候。 更新 我试图获得更多有关该错误的信息: 我知道问题出在哪里: 实际上,该表对同一张表有2 fk ,而我,我坚持的是 问题答案: 可能引发了异常。这意味着该子句中没有要回滚的活动事务。这就是为什么

    • 问题内容: 是否可以使用Spring Data JPA(由Hibernate作为JPA提供者支持)并同时直接使用Hibernate? 问题是,当我使用JpaTransactionManager时,无法使用检索当前会话。当我切换到HibernateTransaction Manager时,JPA存储库无法提交更改。 这是我的Spring上下文的一部分(在该上下文中,我无法使用直接的Hibernate

    • 我正在尝试将一条记录插入到名为 user 的表中。我尝试排除故障的方法是,它位于我的类中。我正在使用和来完成此操作。我仍然无法将用户插入到表中。任何这方面的帮助将不胜感激。 UserRepositoryImpl 用户存储库自定义 用户存储库

    • 我有一个部署在JBoss中的spring boot+Hibernate+Log4j的web应用程序。如果我们在application.properties中使用“spring.jpa.show-sql=true”,那么所有的hibernate sql查询都将记录在server.log中。根据Hibernate Log4j指令,我们需要将该属性变为false,以便按照Log4j配置将sql语句记录在