Hibernate Forward Engineering - Create Tables from Entity Classes
- Details
- Written by Nam Ha Minh
- Last Updated on 23 May 2020   |   Print Email
When using Hibernate framework, we usually create entity classes to map with tables in the database. This process is called reverse engineering, which is suitable if the database does exist before the coding. Otherwise, we should use Hibernate forward engineering which creates entity classes first and then let Hibernate automatically create tables in the database – so we can save time and avoid mistakes if create tables manually.
To use Hibernate forward engineering, you need to specify the hibernate.hbm2ddl.auto property in Hibernate configuration file. For example:
<hibernate-configuration> <session-factory> … <property name="hibernate.hbm2ddl.auto">create</property> … </session-factory> </hibernate-configuration>
In case you’re using Spring Boot with Spring Data JPA and Hibernate, add the following entry in the application.properties file:
spring.jpa.hibernate.ddl-auto=create
Now, let’s understand some possible values for this property.
1. Possible values of the property hibernate.hbm2ddl.auto
You can specify one of the following values for the hibernate.hbm2ddl.auto property:
- create: let Hibernate creates tables according to the mapped entity classes. Hibernate attempts to drop the tables if exist. So use this value when you want to create the database for the first time. If you use it in the 2nd time, previous data will be lost.
- create-drop: use this value if you want Hibernate to create tables and then drop them when the session ends. This value is suitable for running unit tests on a temporary database or in-memory database, without the need to keep data.
- update: use this value in case you want to apply changes in the entity classes into the database, e.g. adding new columns to an existing table, or create additional tables from new entity classes. Note that Hibernate won’t alter the tables if you change only attributes of columns, e.g. nullability, unique, length, and the like.
- validate: use this value if you want Hibernate to validate the database schema against the mapped entity classes. Upon testing, I found that Hibernate checks only if the tables exist or not. If not, it throws SchemaManagementException – reporting tables missing.
- none: tell Hibernate do not touch the database schema. Use this value when the database is stable and in production mode.
2. Specify exact database dialect
Hibernate uses the SQL syntax of the target database to create tables accordingly, so it’s important to specify database dialect information exactly matches the type of the underlying database. Otherwise, you will get error or undesired behaviors.
For example, for MySQL database:
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
Or:
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
For Oracle database:
<property name="dialect">org.hibernate.dialect.Oracle8iDialect</property>
Check this document to see the list of database dialect supported by Hibernate framework.
3. Hibernate Forward Engineering Example
Now, let me walk you through the development process of a Java project to demonstrate Hibernate forward engineering.
Create an entity class Product with the following code:
package net.codejava; import javax.persistence.*; @Entity @Table(name = "products") public class Product { @Id @Column(name = "product_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(name = "name", length = 128, nullable = true, unique = false) private String name; @Column(name = "price", precision = 10, scale = 2) private float price; @Column(name = "enabled", columnDefinition = "tinyint default 1") private boolean enabled; @Column(length = 512, nullable = true) private String description; // getters and setters are not shown, for brevity }
As you can see, we use JPA annotations to map this entity class with a database table (not exists before). If the table name/field name name is as same as the table name/column name, then you don’t have to specify the name attribute.
Then create the Hibernate configuration file hibernate.cfg.xml as follows:
<?xml version="1.0" encoding="UTF-8"?> <hibernate-configuration> <session-factory> <property name="connection.url">jdbc:mysql://localhost:3306/testdb</property> <property name="connection.username">root</property> <property name="connection.password">password</property> <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.hbm2ddl.auto">create</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <mapping class="net.codejava.Product" /> </session-factory> </hibernate-configuration>
Here, we specify create for the hibernate.hbm2ddl.auto property so Hibernate will create a table from the entity class. Note that you should create a database schema named testdb in the database.
Next, code a simple test program as follows:
package net.codejava; import org.hibernate.*; import org.hibernate.boot.*; import org.hibernate.boot.registry.*; public class HibernateForwardEngineeringTest { public static void main(String[] args) { final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .configure() // configures settings from hibernate.cfg.xml .build(); try { SessionFactory factory = new MetadataSources(registry) .buildMetadata().buildSessionFactory(); Session session = factory.openSession(); Transaction transaction = session.beginTransaction(); Product product = new Product(); product.setName("iPhone 7 Plus"); product.setDescription("A good smartphone"); product.setPrice(1299.89f); product.setEnabled(true); session.save(product); transaction.commit(); session.close(); factory.close(); } catch (Exception ex) { System.out.println(ex.getMessage()); ex.printStackTrace(); StandardServiceRegistryBuilder.destroy(registry); } } }
This program simply persists a Product object to a session, which results in inserting a new row into the database table. Run this program and you would see Hibernate prints the following SQL statements:
drop table if exists products create table products ( product_id integer not null auto_increment, description varchar(512), enabled tinyint default 1, name varchar(128), price float, primary key (product_id) ) engine=InnoDB insert into products (description, enabled, name, price) values (?, ?, ?, ?)
Check the database (use MySQL Workbench) to verity the table actually created with one row inserted. Then play with other values of the hibernate.hbm2ddl.auto property: create-drop, update, validate and none.
Conclusion
Hibernate forward engineering is a convenient feature that helps programmer save time and avoid mistakes with regarding to database schema creation. You can use different value of the hibernate.hbm2ddl.auto property in different phases of the development process to get the most out of it.
Watch the video version:
Other Hibernate Tutorials:
- Java Hibernate Reverse Engineering Tutorial with Eclipse and MySQL
- Java Hibernate JPA Annotations Tutorial for Beginners
- Hibernate Hello World Tutorial for Beginners with Eclipse and MySQL
- Hibernate One-to-One Association on Primary Key Annotations Example
- Hibernate One-to-Many Using Join Table XML Mapping Example
- Hibernate Many-to-Many Association with Extra Columns in Join Table Example
- Hibernate Enum Type Mapping Example
- Hibernate Binary Data and BLOB Mapping Example
- Hibernate Basics - 3 ways to delete an entity from the datastore
- Hibernate Query Language (HQL) Example
Comments