Java’s persistence API (JPA) makes object-relational mapping very convenient. Using Hibernate, tables and sequences are generated automatically which speeds up development significantly. However, in production systems automatic schema creation isn’t desired. In many cases you would want to tune the schema a bit, like adding an index for speeding up common access paths, renaming constraints and the like. Additionally, an application should run with as little DB privileges as possible, so it is possible that CREATE TABLE
is simply not permitted.
[UPDATE: See this article for a pure maven solution.]
The usual approach is to create a DDL script containing the required CREATE
commands and execute it on the database before deploying the application. Unfortunately, this is a large task if you have many entities and with foreign key constraints, the order of commands matters. So it would be nice if we could generate a working DDL script from our JPA annotations that can be adjusted manually.
Using Hibernate and the hibernatetool
Ant task, this is possible. In the following example, I’ll show how to configure a Maven project which used the antrun plugin to execute hibernatetool from within Maven.
First of all, we have to attach the antrun plugin to Maven’s lifecycle. Add the following to your pom.xml
:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>process-classes</id> <phase>process-classes</phase> <configuration> <tasks> <ant antfile="src/main/ant/build.xml" inheritRefs="true"> <target name="schemaexport"/> </ant> </tasks> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-tools</artifactId> <version>3.2.0.beta9a</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.2.1.ga</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> </dependencies> </plugin> </plugins> </build>
The plugin configuration references an external build.xml
file which contains the hibernatetool invocations. Create a directory src/main/ant
and add the following build.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <project> <!-- Generate DDL files for schema creation. --> <target name="schemaexport"> <taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask"/> <hibernatetool destdir="target"> <classpath refid="maven.compile.classpath"/> <!-- Use JPA annotations, as opposed to Hibernate's hbm files. If there are multiple persistence units, specify the correct one using the "persistenceunit" attribute. --> <jpaconfiguration /> <!-- Write all CREATE statements to a file. --> <hbm2ddl drop="false" create="true" export="false" outputfilename="schema-create.ddl" delimiter=";" format="true"/> <!-- Write all DROP statements to a different file. --> <hbm2ddl drop="true" create="false" export="false" outputfilename="schema-drop.ddl" delimiter=";" format="true"/> </hibernatetool> </target> </project>
Now you can run mvn generate-classes
and you will find two DDL files in the target
directory: One for creating and one for dropping all tables.
Good article.
One question.
Can hibernate3:hbm2ddl from hibernate3-maven-plugin does the same as ant for you here? Ant invocation is considered to slow down maven execution time.
Unfortunately, I never got that plugin working, so I chose ant. If you know a way I’d appreciate to hear how you did it. Thanks!
This works for me:
http://lystochok.org.ua/2007/12/11/how-to-generate-ddl-schema-with-maven2/
OMax
Thanks a lot! I’ll try it as soon as my holidays are over and I’m back at work.
Cheers,
Matthias
Did you get it to work with maven2 only? Because lystochok’s post doesn’t seem to exist anymore. Thank you!
Yes, I finally got it working. Please see my latest article for the solution.
Pingback: So Much for 2010 « Unmaintainable
Nice article.
However, why not simply let the database be created in the dev environment first by Hibernate, export as SQL and tweak as desired?
That works, too. However, there’s no standard mechanism to extract the schema from a database. The solution presented here works for all database systems and it can run as part of your build process without needing access to a database instance.