3

I have a spring-boot/spring-data-rest project. I'd like to be able to use in-memory/normal db depending on some env variable. Is this possible?

Right now I'm just commenting out my application config with parameters for production database like that

#spring.jpa.database=POSTGRESQL
#spring.datasource.platform=postgres
...
5
  • Testing on a different DBMS than you use in production is usually not a good idea. The tests are more or less meaningless due to differences in behavior between the various DBMS. Commented Aug 24, 2015 at 9:30
  • 1
    Seriously? What differences are you talking about specifically? I mean they all have transactions. The only difference I see basically is speed. Although h2 doesn't executing onPostSave hook somehow... Commented Aug 24, 2015 at 9:32
  • e.g. some DBMS allow multiple NULL values in a unique index others don't. select * from (select x,y from foo) where x > 0 will work in e.g. H2 or HSQLDB, but not in Postgres. Postgres has a full outer join, H2 does not. where (a,b) in (select c,d from bar) works in Postgres and HSQLDB, but not in H2. select a,b from foo f join bar b on f.a = b.b will work in HSQLDB, but fails in Postgres and H2 (if both foo and bar have columns named a and b). Commented Aug 24, 2015 at 9:38
  • Well... You should use ORM for queries (it will work, will it?). If it's not performant enough I think you should choose different sql at runtime based on what db you use. This is more code, but IMHO it's worth the trouble. Commented Aug 24, 2015 at 9:41
  • Creating a "DBMS independent" application (e.g. through an Obfuscated Relational Model) simply means the application runs equally bad on all platforms. You will run into problems in the long run. Plus you limit yourself to the least common denominator so you can never use any DBMS specific features to make things easier (less code!) or run faster. Commented Aug 24, 2015 at 9:43

3 Answers 3

3

I strongly suggest a read on Spring Profiles and how Spring Boot utilizes that to load different config files.

So basically you have 2 options

  1. Use profiles
  2. Use different application.properties per environment in one of the specified locations.

For option 1 to work put some defaults in your application.properties (probably the production ones). And create an application-dev.properties which contains your in-memory stuff.

Now before starting your application either create an environment variable called spring.active.profiles=dev or pass it along starting your application -Dspring.active.profiles=dev.

Now when you start your application, both the application.properties and application-dev.properties will be loaded. The latter overriding any properties from the default one.

Sign up to request clarification or add additional context in comments.

2 Comments

I haven't tried your solution, because I've used a little bit different solution. I've moved from .properties to .yaml and defined profile "production" there. Then I've used SPRING_PROFILES_ACTIVE env variable to set active profile.
That is basically the same, but in a YAML approach :).
1

Yes it is possible using Spring profile.

You can define different profiles and make any of your profile active depending on your requirements.

You can refer Spring Profiles example by @Mkyong.

5 Comments

Right now my config for db is in application.properties and I like it that way. How can use still use it. I probably don't want to configurate db through code and annotations. I've read a little about profiles and it's not clear to me - should I create some yaml file instead of application.properties or what?
You can define different datasources and assign then different profiles(like dev or test etc) and then you can activate any profile.
Could you show simple config for that? I still don't understand where should I define this datasources: in yaml or application.properties?
Sorry I have less knowledge of Spring boot. Right now I am working in Spring-mvc.
Thanks for you help. I've read a little more about profiles and configs. I've moved from application.properties to application.yaml and defined profile there. Then I've used SPRING_PROFILES_ACTIVE env variable to set active profile.
0

I do this configuration using maven. It is possible to create maven profiles with the parameters you want. For example:

<profiles>
<profile>
    <id>db-local</id>
    <properties>
        <spring.profile.name>dbcp</spring.profile.name>
        <hibernate.dialect>org.hibernate.dialect.HSQLDialect</hibernate.dialect>
        <hibernate.driver>org.hsqldb.jdbcDriver</hibernate.driver>
        ...
    </properties>
</profile>

<profile>
    <id>db-central</id>
        <properties>
        <spring.profile.name>dbcp</spring.profile.name>
        <hibernate.dialect>org.hibernate.dialect.Oracle10gDialect</hibernate.dialect>
        <hibernate.driver>oracle.jdbc.driver.OracleDriver</hibernate.driver>
        ...
    </properties>
</profile>

...

Then you can define this variables in your java code or in your xml descriptor as this : ${hibernate.dialect}.

If you do so, then maven has to filter this files before compiling/packaging in order to replace maven variables. This can be done using maven resources plugin or maven war plugin.

Here you are an example of maven filtering:

<plugins>
    <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.4</version>
        <configuration>
            <webResources>
                <resource>
                    <filtering>true</filtering>
                    <directory>src/main/webapp</directory>
                    <includes>
                        <include>WEB-INF/web.xml</include>
                        <include>WEB-INF/springConfig/app-bbdd-dbcp.xml</include>
                        <include>WEB-INF/springConfig/app-security.xml</include>
                    </includes>
                </resource>
            </webResources>
        <configuration>
    </plugin>
</plugins>

You can activate or deactivate spring plugins by means of maven variables.

Here you can see a fully working project as I've described you: https://github.com/malaguna/casiopea

2 Comments

No, I don't want different jars for prod and dev. That's just wrong. Also gradle is so much better =) But thanks for your answer!
This is generally a bad idea imho. You want 1 artifact to go from test to prod. You don't want different artifacts because there is no guarantee that something isn't broken in one of the artificats. So it might function on test but break in prod.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.