1
votes

I have a project where I am using spring-data-jpa with Hibernate and I am writing an integration test which uses an H2 in memory database.

In my DB Script, after the table creation, I am actually run a few insert statements

INSERT INTO COST (paymentType, costValue, costCategory) VALUES ('INTERNATIONAL', 100, 'LICENSES');
INSERT INTO COST (paymentType, costValue, costCategory) VALUES ('INTERNATIONAL', 20, 'HARDWARE');

After running my integration test, I saw that there were 4 entries returned instead of the 2.

The logs confirmed that the test was initialising the datasource twice and I'd like to understand why. Any help would be appreciated.

2017-04-26 12:19:38; LOG_LEVEL="DEBUG"; SOURCE="org.springframework.jdbc.datasource.DriverManagerDataSource"; EVENT_MESSAGE="Creating new JDBC DriverManager Connection to [jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:create-db.sql']"

In my Spring config file, annotated with @EnableJpaRepositories, I then create the persistence related beans as shown below

    @Bean
public JpaTransactionManager transactionManager() {
    if (transactionManager == null) {
        transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
    }
    return transactionManager;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    if (entityManagerFactoryBean == null) {

        entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setJpaProperties(hibProperties());      
    }
    return entityManagerFactoryBean;
}

@Bean
public DriverManagerDataSource dataSource() {

    if (dataSource == null) {
        dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(env.getRequiredProperty(DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(DATABASE_PASSWORD));
    }
    return dataSource;
}    

The properties are

db.driver = org.h2.Driver
db.url = jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM \'classpath:create-db.sql\'
db.username = cost
db.password = cost
entitymanager.packages.to.scan = com.somecompany.cost
hibernate.dialect = org.hibernate.dialect.H2Dialect
hibernate.show_sql = false
hibernate.format_sql = false

Cheers Kris

2
Would you show you hibProperties() method, and your DATABASE_URLEssex Boy
I have edited the original post to include them..thankskrisrr3

2 Answers

0
votes

After removing 'DB_CLOSE_DELAY=-1' from the db.url property, I started to get the correct number of data rows; which is 2.

However, I checked the logs and there were still 2 instances of the datasource being created and I am not sure why the instances are not being reused

The log lines are below

Line 1616

2017-04-27 09:41:58; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory"; EVENT_MESSAGE="Registering IdentifierGenerator strategy [enhanced-table] -> [org.hibernate.id.enhanced.TableGenerator]"
2017-04-27 09:41:58; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.cfg.Configuration"; EVENT_MESSAGE="Preparing to build session factory with filters : {}"
2017-04-27 09:41:58; LOG_LEVEL="DEBUG"; SOURCE="org.springframework.jdbc.datasource.DriverManagerDataSource"; EVENT_MESSAGE="Creating new JDBC DriverManager Connection to [jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'classpath:create-db.sql']"

Line 2331

2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.hql.internal.ast.ErrorCounter"; EVENT_MESSAGE="throwQueryException() : no errors"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.SQL"; EVENT_MESSAGE="select cost0_.costId as costId1_0_, cost0_.costCategory as costCate2_0_, cost0_.costValue as costValu3_0_, cost0_.paymentType as paymentT4_0_ from Cost cost0_ where cost0_.paymentType=?"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.engine.jdbc.internal.LogicalConnectionImpl"; EVENT_MESSAGE="Obtaining JDBC connection"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.springframework.jdbc.datasource.DriverManagerDataSource"; EVENT_MESSAGE="Creating new JDBC DriverManager Connection to [jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'classpath:create-db.sql']"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.engine.jdbc.internal.LogicalConnectionImpl"; EVENT_MESSAGE="Obtained JDBC connection"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.loader.Loader"; EVENT_MESSAGE="Result set row: 0"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.loader.Loader"; EVENT_MESSAGE="Result row: EntityKey[com.somecompany.domain.Cost#1]"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.loader.Loader"; EVENT_MESSAGE="Result set row: 1"
2017-04-27 09:41:59; LOG_LEVEL="DEBUG"; SOURCE="org.hibernate.loader.Loader"; EVENT_MESSAGE="Result row: EntityKey[com.somecompany.domain.domain.Cost#2]
0
votes

You don't need to create your own dataSource, Spring is already doing this. You're datasource is the 2nd one. This is why your script is being run twice, because the JDBC URL is being called twice.

I suggest:

1) Remove you dataSource bean.

2) Change your JDBC URL to

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"

3) Rename your create-data.sql to data.sql and add it to your resources directory so it's in the classpath.

Spring should do the rest see here for the manual.