How to configure spring-boot to use file based H2 database

bitboy picture bitboy · Jun 19, 2016 · Viewed 76.9k times · Source

I have successfully created a spring boot application that uses the H2 embedded database in-memory. I would now like to change this to a file based version that will persist.

I have tried just changing the spring.datasource.* properties in my application.properties file and they look something like this:

spring.datasource.url=jdbc:h2:file:~/test;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driverClassName=org.h2.Driver`  

It seems like spring boot just ignores these settings because it just starts as follows:

o.s.j.d.e.EmbeddedDatabaseFactory        : Starting embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'

My pom.xml contains the following dependencies that may be relevant to this post:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.3.5.RELEASE</version>
</parent>
....
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency> 
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

My understanding from the documentation and a number of posts is that the configuration should just work but no luck for me. Just to prevent some of the basic errors I have tried and checked the following:

  1. My application properties is in the classspath:
  2. I have tried to exclude the auto configuration in annotation @EnableAutoConfiguration
  3. I have tried to inject a dataSource bean with combinations of annotation @Primary, @ConfigurationProperties(prefix = "spring.datasource") and setting the properties programmatically with DataSourceBuilder. This causes other errors related to the type being null.

Seems like I am missing a key concept or something. Can anyone help.

UPDATE 1: Extract from my auto configuration report:

Positive matches:
-----------------

    DataSourceAutoConfiguration matched
  - @ConditionalOnClass classes found: javax.sql.DataSource,org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType (OnClassCondition)

   DataSourceAutoConfiguration.DataSourceInitializerConfiguration matched
  - @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer; SearchStrategy: all) found no beans (OnBeanCondition)

   DataSourceAutoConfiguration.EmbeddedConfiguration matched
  - embedded database H2 detected (DataSourceAutoConfiguration.EmbeddedDataSourceCondition)
  - @ConditionalOnMissingBean (types: javax.sql.DataSource,javax.sql.XADataSource; SearchStrategy: all) found no beans (OnBeanCondition)

   DataSourceAutoConfiguration.JdbcTemplateConfiguration matched
  - existing auto database detected (DataSourceAutoConfiguration.DataSourceAvailableCondition)

   DataSourceAutoConfiguration.JdbcTemplateConfiguration#jdbcTemplate matched
  - @ConditionalOnMissingBean (types: org.springframework.jdbc.core.JdbcOperations; SearchStrategy: all) found no beans (OnBeanCondition)

   DataSourceAutoConfiguration.JdbcTemplateConfiguration#namedParameterJdbcTemplate matched
  - @ConditionalOnMissingBean (types: org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; SearchStrategy: all) found no beans (OnBeanCondition)

   DataSourceTransactionManagerAutoConfiguration matched
  - @ConditionalOnClass classes found: org.springframework.jdbc.core.JdbcTemplate,org.springframework.transaction.PlatformTransactionManager (OnClassCondition)

   DataSourceTransactionManagerAutoConfiguration.TransactionManagementConfiguration matched
  - @ConditionalOnMissingBean (types: org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration; SearchStrategy: all) found no beans (OnBeanCondition)

    H2ConsoleAutoConfiguration matched
  - @ConditionalOnClass classes found: org.h2.server.web.WebServlet (OnClassCondition)
  - found web application StandardServletEnvironment (OnWebApplicationCondition)
  - matched (OnPropertyCondition)

   HibernateJpaAutoConfiguration matched
  - @ConditionalOnClass classes found: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean,org.springframework.transaction.annotation.EnableTransactionManagement,javax.persistence.EntityManager (OnClassCondition)
  - found HibernateEntityManager class (HibernateJpaAutoConfiguration.HibernateEntityManagerCondition)

Negative matches:
-----------------

    DataSourceAutoConfiguration.NonEmbeddedConfiguration did not match
  - missing supported DataSource (DataSourceAutoConfiguration.NonEmbeddedDataSourceCondition)

`

UPDATE 2: added actuator and looked at endpoint /configprops. What is interesting here is that my config has been taken and the database exists but when the application runs it does not use this dataSource.

"spring.datasource.CONFIGURATION_PROPERTIES":
    {"prefix":"spring.datasource",
     "properties":{
        "schema":null,
        "data":null,
        "xa":{"dataSourceClassName":null,
               "properties":{}
             },
        "type":null,
        "separator":";",
        "url":"jdbc:h2:file:~/test;DB_CLOSE_ON_EXIT=FALSE",
        "platform":"all",
        "continueOnError":false,
        "jndiName":null,               
        "sqlScriptEncoding":null,
        "password":"******",
        "name":"testdb",
        "driverClassName":"org.h2.Driver",
        "initialize":true,
        "username":"test"
        }
    }  

Answer

Avinash picture Avinash · Nov 10, 2017

I am adding this answer to avoid confusion and further research.

Actually I have the same problem and none of the answer worked for me completely rather than the mix for some answers worked.

Here is the minimal configuration which is required to persist H2 db in spring boot.

application.properties

# H2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Datasource
spring.datasource.url=jdbc:h2:file:~/spring-boot-h2-db
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update

Here spring.jpa.hibernate.ddl-auto=update does the trick. Nothing else is required.

No need to add spring-boot-starter-jdbc in pom.xml

No need to add any parameter in jdbc url.