All Articles

How to generate schema when writing Hibernate standalone app

hibernate standalone

Recently I played with Hibernate as I need a really simple application that would be capable to write and read data from the database while it would be portable for use with JDBC drivers from different vendors. I didn’t want to write an abstract layer which would be dependent on particular JDBC driver and need to be recompiled with each. I just wanted to add a driver on the classpath, change a property and let it run. No recompilation. And it’s what the Hibernate solved for me at the end.

On top of that, I wanted Hibernate to create the database schema. Mine is pretty simple thus the entity could be scanned and created based on its attributes.

More precisely what I wanted

  • a standalone java application

  • code being independent on specific JDBC driver

  • generating database schema independently on specific SQL syntax. Normally the CREATE the command could differ database from the database.

  • being able to influence database name before starting of the java application (e.g. by some descriptor or system property)

  • saving and querying data to/from the database

Two possible solution with the Hibernate

While elaborating with Hibernate I found two way how to achieve my goal.

The first way was using JPA with persistence.xml definition of database connection properties and entity used as schema. Then asking javax.persistence.Persistence to generate the schema.

The second was using Hibernate API programmatically creating service registry builder and using schema exporter to generate the schema.

The demand for dynamically changing the table name was done by implementing naming strategy that adding a suffix to the original table name. This approach was taken in both cases. In one the strategy to be used as defined in the persistence.xml and using property hibernate.physical_naming_strategy while in the second case the strategy was provided to the MetadataBuilder.

Running the code example

I played with the both approaches under the project https://github.com/ochaloup/hibernate-standalone.

If you want to run the example you need to

  1. get the repo git clone https://github.com/ochaloup/hibernate-standalone (use the correct branch to work with either jpa-and-xml or hibernate-programatic-approach)

  2. package it (maven is configured to create fat jar containing hibernate library): mvn clean package

  3. get the JDBC driver (expected you will use the PostgreSQL one: https://jdbc.postgresql.org)

  4. run PostgreSQL database (you can use docker to run it: docker run -p 5432:5432 --rm -ePOSTGRES_USER=test -e POSTGRES_PASSWORD=test postgres:9.4 -c max-prepared-transactions=110 -c log-statement=all)

  5. start the java program at root cd hibernate-standalone

    1. java -cp target/hibernate-standalone-1.0-SNAPSHOT-jar-with-dependencies.jar:<./postgresql-driver.jar>:. cz.chalda.Main

Note

You can watch names of all tables at PostgreSQL with query

SELECT *  FROM information_schema.tables WHERE table_type = 'BASE TABLE'
  AND table_schema = 'public' ORDER BY table_type, table_name;

JPA persistence.xml approach

This approach could be investigated at the branch https://github.com/ochaloup/hibernate-standalone/tree/jpa-and-xml.

The all connection configuration is defined in the persistence.xml file. Here we define connection properties for the database, the dialect which defines how to query for the JDBC driver and there is a defined table naming strategy if needed.

The example then uses the descriptor file hibernate.hbm.xml which defines <entity-mapping> attribute. This configuration file is placed in the root of the project and is referred in the persistence.xml with the absolute path of ./. That means when running java -cp …​ <program-name> the program will expect the mapping file at the place the java is run at.\+ That’s why the mapping file is placed at the root and defines different table name for you too (up to the fact of the existence of the naming strategy).

For interest, the example contains the mapping file hibernate.hbm.xml.out containing the whole mapping of the entity but with table name redefinition.

The logic of creating the database schema and the entity save and the load is hidden in the class cz.chalda.Main. There you can see the usage of javax.persistence.Persistence to generate the database schema and then to get the PersistenceUnit for being able to save and load the entity.

Programmatic hibernate approach

There is no configuration files in this case. We configure all at cz.chalda.Main file.

The connection is configured via StandardServiceRegistryBuilder and it is defined credentials and the dialect too. Next is the usage of the MetadataBuilder class which offers registration for enhancement of the PhysicalNamingStrategyStandard to change table name with suffix. The last part is using SchemaExport for database schema creation while metadata is used again for getting SessionFactory and Session for being able to create and update the database data.

Summary

Thanks for attention.

Both approaches offer a way to run a standalone java app with Hibernate to save time to develop an integration layer to different JDBC drivers while showing some Hibernate extension points to be used for further application tuning.

Published Jul 18, 2018

Developer notes.