2017-12-26 3 views
6

Ich habe ein Spring Data JPA-Repository, das Hibernate als Provider verwendet. Ich möchte SQL-Anweisungen protokollieren, aber das kann ich nicht erreichen. Ich habe versucht, verschiedene Lösungen:Aktiviere SQL-Statements, die mit Hibernate und Spring Data protokollieren JPA

  • Sets showSql auf true in meinem HibernateJpaVendorAdapter
  • hinzufügen log4j.logger.org.hibernate.SQL = DEBUG meine log4j.properties Datei (es ist erwähnenswert, dass log4j.logger.org zu erwähnen. hibernate = INFO haben fügen Sie einige Logging-Informationen aber log4j.logger.org.hibernate.SQL = DEBUG tat nicht)

Hier sind meine Klassen und Konfigurationsdateien:

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); 
    } 

} 

database.properties

# 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; 

} 

EmployerRepository.java

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

} 

EmployerRepositoryIT.java

/** 
* {@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())); 
    } 

} 

log4j.properties

# 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 

Warum ist es, dass die bisherigen Lösungen nicht funktioniert? Gibt es eine Art Inkompatibilität zwischen Spring Data JPA und Hibernate SQL-Protokollierungskonfiguration?

EDIT: Ich versuchte beide Lösungen in Kommentaren vorgeschlagen, aber keiner von ihnen funktioniert. Ich versuchte auch, die Datenbank zu ändern, die ich verwendete (H2 für HSQL) oder Hibernate Dialekt zu spezifizieren, aber das hat nicht funktioniert. Tatsächlich wird der Hibernate-Dialekt für einige Datenbanken automatisch gefunden, wenn Spring verwendet wird.

EDIT 2: Ich habe versucht, Protokollierungsebene des RootLogger auf TRACE zu ändern. Ich versuche auch explizit einen Schwellenwert für den Appender anzugeben. Und schließlich habe ich versucht, JpaProperties mit showSql = true hinzuzufügen, aber keiner von ihnen hat den Trick gemacht. Ich denke, dass es etwas wirklich Offensichtliches zu tun gibt, dass ich vermisse, um die komplette Situation zu entsperren: -/

EDIT 3: Der Aufruf des Loggers direkt wie im folgenden Test funktioniert. Ich wurde mich fragen, ob es einen Tippfehler oder etwas gibt, das Hibernate daran hindert, den Logger zu benutzen.

@Test 
public void delete() { 
    LoggerFactory.getLogger("org.hibernate.SQL").debug("delete()"); 
    repository.delete(MICROSOFT); 
    assertNull(entityManager.find(Employer.class, MICROSOFT.getId())); 
} 

Hier sind die resultierenden Protokolle:

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[email protected]1f28c152, org.springframewor[email protected]7d907bac, org.springfra[email protected]7791a895, org.springframew[email protected]3a5ed7a6, org.sp[email protected]6325a3ee]10:33:45,376 INFO GenericApplicationContext:589 - Refreshing [email protected]93d195: 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 [DefaultTe[email protected] testClass = EmployerRepositoryIT, testInstance = be.dupirefr[email protected]1460c81d, testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [o[email protected]5b22b970]; rollback [true] 
10:33:49,468 DEBUG SQL:83 - delete() 
10:33:49,512 INFO TransactionContext:137 - Rolled back transaction for test context [[email protected] testClass = EmployerRepositoryIT, testInstance = be.dupirefr[email protected]1460c81d, testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] 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 [email protected]93d195: 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' 

EDIT 3: ich, was endlich heraus passieren. Ich habe festgestellt, dass bei fehlgeschlagenen Tests SQL-Abfragen in den Protokollen ausgegeben wurden.Und indem ich ein wenig meine Log4j-Eigenschaften abstimmte, sah ich, dass sie wie erwartet vom Hibernate Logger kamen.

Erfolgreiche Vorgänge führten jedoch keine Protokolle aus. Und das, weil sie die Datenbank nicht erreichen. Alles passiert innerhalb des Entity Managers und somit wird kein SQL benötigt. Jetzt weiß ich, dass ich nur ein Problem mit meiner H2-Datenbank habe, die ich herausfinden muss.

+0

Versuch durch Zugabe von 'logging.level.org.hibernate.SQL = DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder = TRACE' in der porperties Datei und sehen? –

+0

Sie sagten, 'log4j.logger.org.hibernate = INFO' habe etwas Logging hinzugefügt, aber' log4j.logger.org.hibernate.SQL = DEBUG' nicht. Hast du versucht ... 'log4j.logger.org.hibernate = DEBUG'? Oder gibt es oben einen Tippfehler? – dimwittedanimal

+0

@AhmedRaaj: Diese Eigenschaften müssen in einer Spring-Eigenschaftendatei (wie application.properties) enthalten sein. Ich habe keine, ich benutze Spring Boot nicht. Ich habe versucht, log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder = TRACE zu meiner log4j.properties-Datei hinzuzufügen, aber da das Ziel dieses Loggers binierte Parameter anzuzeigen, hatte es keine Wirkung. –

Antwort

1

Seit Blick auf den Code Sie nicht, es scheint zur Verfügung gestellt zu schneiden, ich habe es mit einigen Anweisungen versuchen werde, wie dies zu debuggen.

  1. Lassen Sie die Änderungen wie in meiner ersten Antwort angegeben.

  2. Stellen Sie sicher, dass die von Ihnen angezeigte Eigenschaftendatei die Loggerkonfiguration steuert. Für diese Änderung, zum Beispiel, das Ausgabeformat und prüfen, ob es die Ausgabe wie erwartet beeinflusst.

  3. Suchen Sie eine relevante Logging-Anweisung in Hibernate. Setzen Sie dort einen Haltepunkt. Debuggen, bis Sie den Ort finden, wo die Protokollanweisung verworfen wird. Vergleichen Sie die an Ihrer Konfiguration beteiligten Datenstrukturen, um herauszufinden, was falsch läuft.

+0

Ich werde das versuchen :-). Ich habe es vorher nicht erwähnt, aber das Setzen der Protokollierungsstufe von RootLogger auf TRACE hat einige Protokolle hinzugefügt, aber nicht die SQL-Abfragen. –

+0

Ich habe versucht, einen Haltepunkt der ersten Zeile meines Tests zu setzen und den org.hibernate.SQL Logger dorthin zu bringen. Es scheint gut konfiguriert zu sein. Ich werde immer noch versuchen, eine Logging-Anweisung in Hibernate-Klassen zu bekommen, aber es ist nicht so einfach wie es scheint :-) –

+0

Ich hatte keine Zeit, weiter zu graben, und ich habe immer noch keine Lösung. Aber angesichts der Menge an Hilfe, die Sie mir gegeben haben, habe ich beschlossen, Ihnen das Kopfgeld für diese Frage zu geben :-) –

3

ersetzen:

log4j.rootLogger=INFO, stdout 

Mit

log4j.rootLogger=TRACE, stdout 

Und möglicherweise

log4j.logger.org.hibernate.type.descriptor.sql=TRACE 

hinzufügen Wenn Sie auch die Werte von Bind-Variablen wollen.

Sie hatten Ihre Protokollierung fein konfiguriert, aber Ihr appender nur wurde Abholung INFO und SQL-Anweisungen angemeldet sind DEBUG

+0

Das scheint ja echt :-).Ich werde das heute Abend versuchen und mit dem Ergebnis zu dir zurückkommen! –

+0

Ich habe es gerade versucht, aber es hat nicht funktioniert. Nachdenken darüber, was erwartet wurde, da es nur die Logging-Ebene des Root-Loggers und nicht die Schwelle des Appenders ändert (was ich übrigens auch versuchte, zu ändern, aber auch nicht funktionierte). Danke für den Versuch, obwohl. –

+0

Nicht sicher, was Sie mit der Schwelle des Appenders meinen. Der Appender hat keinen, außer durch seine Konfiguration für den Root-Logger. –

1

mit Try this:

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

private Properties properties() { 
    Properties properties = new Properties(); 
    properties.put("hibernate.show_sql", "true"); 
    properties.put("hibernate.format_sql", "true"); 
    return properties; 
} 

UPDATE

Ich hatte eine ähnliche config klasse wie deine, da ich update auf frühling boot habe ich diese klasse entfernt und alle die config in die application.properties datei. Meine config:

#DataSource 
spring.datasource.driver-class-name=org.postgresql.Driver 
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb 
spring.datasource.username=postgres 
spring.datasource.password=123456 

#Hibernate 
spring.jpa.properties.hibernate.show_sql=true 
spring.jpa.properties.hibernate.format_sql=true 
spring.jpa.properties.hibernate.jdbc.batch_size=10 
spring.jpa.properties.hibernate.id.new_generator_mappings=true 

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect 
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext 
+0

Hat auch nicht funktioniert :-( –

+0

Werfen Sie einen Blick auf mein Update –

+0

Sie haben ein paar Dinge mehr als ich habe (Dialekt oder Sitzungskontext), aber sind diese mit dem Problem verbunden? Dialekt ist nicht, es wird automatisch von Frühling gefunden (und ich habe versucht, es explizit für den Fall anzugeben, änderte nichts) –