In the previous article, we have discussed a below three inheritance strategies:
In this article, we’ll look into Hibernate/JPA table per class inheritance.
In a Table per class inheritance strategy, each concrete subclass has its own table containing both the subclass and the base class properties.
Let's demonstrates TABLE_PER_CLASS inheritance strategy with a complete hibernate example.
Technologies and tools used
- Hibernate 5.3.7.Final
- IDE - Eclipse Noen
- Maven 3.5.3
- JavaSE 1.8
- MySQL - 8.0.13
Development Steps
- Create a Simple Maven Project
- Project Directory Structure
- Add jar Dependencies to pom.xml
- Creating the JPA Entities
- Create a Hibernate configuration file - hibernate.cfg.xml
- Create a Hibernate utility class
- Create the Main class and Run an Application
1. Create a Simple Maven Project
Use How to Create a Simple Maven Project in Eclipse article to create simple Maven project in Eclipse IDE.
2. Project Directory Structure
The project directory structure for your reference -
3. Add jar Dependencies to pom.xml
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.javaguides.hibernate</groupId>
<artifactId>hibernate-tutorial</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>hibernate-inheritance-tableperclass</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.7.Final</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
4. Creating the JPA Entities
Let's define the following Account base class:
Account.java
package net.javaguides.hibernate.entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@Entity(name = "Account")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String owner;
private double balance;
private double interestRate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public double getInterestRate() {
return interestRate;
}
public void setInterestRate(double interestRate) {
this.interestRate = interestRate;
}
}
CreditAccount.java
package net.javaguides.hibernate.entity;
import javax.persistence.Entity;
@Entity(name = "CreditAccount")
public class CreditAccount extends Account {
private double creditLimit;
public double getCreditLimit() {
return creditLimit;
}
public void setCreditLimit(double creditLimit) {
this.creditLimit = creditLimit;
}
}
DebitAccount.java
package net.javaguides.hibernate.entity;
import javax.persistence.Entity;
@Entity(name = "DebitAccount")
public class DebitAccount extends Account {
private double overdraftFee;
public double getOverdraftFee() {
return overdraftFee;
}
public void setOverdraftFee(double overdraftFee) {
this.overdraftFee = overdraftFee;
}
}
5. Create a Hibernate configuration file - hibernate.cfg.xml
The configuration file contains information about the database and mapping file. Conventionally, its name should be hibernate.cfg.xml.
Let's create an XML file named as hibernate.cfg.xml under resources folder and write the following code in it.
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- JDBC Database connection settings -->
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate_db?useSSL=false</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool settings ... using built-in test pool -->
<property name="connection.pool_size">1</property>
<!-- Select our SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Echo the SQL to stdout -->
<property name="show_sql">true</property>
<!-- Set the current session context -->
<property name="current_session_context_class">thread</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create-drop</property>
<!-- dbcp connection pool configuration -->
<property name="hibernate.dbcp.initialSize">5</property>
<property name="hibernate.dbcp.maxTotal">20</property>
<property name="hibernate.dbcp.maxIdle">10</property>
<property name="hibernate.dbcp.minIdle">5</property>
<property name="hibernate.dbcp.maxWaitMillis">-1</property>
<mapping class="net.javaguides.hibernate.entity.CreditAccount" />
<mapping class="net.javaguides.hibernate.entity.DebitAccount" />
</session-factory>
</hibernate-configuration>
6. Create a Hibernate utility Class
Create a helper class to bootstrap hibernate SessionFactory. In most Hibernate applications, the SessionFactory should be instantiated once during application initialization. The single instance should then be used by all code in a particular process, and any Session should be created using this single SessionFactory. The SessionFactory is thread-safe and can be shared; a Session is a single-threaded object.
The bootstrapping API is quite flexible, but in most cases, it makes the most sense to think of it as a 3 step process:
- Build the StandardServiceRegistry
- Build the Metadata
- Use those 2 to build the SessionFactory
package net.javaguides.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateUtil {
private static StandardServiceRegistry registry;
private static SessionFactory sessionFactory;
public static SessionFactory getSessionFactory() {
if (sessionFactory == null) {
try {
// Create registry
registry = new StandardServiceRegistryBuilder().configure().build();
// Create MetadataSources
MetadataSources sources = new MetadataSources(registry);
// Create Metadata
Metadata metadata = sources.getMetadataBuilder().build();
// Create SessionFactory
sessionFactory = metadata.getSessionFactoryBuilder().build();
} catch (Exception e) {
e.printStackTrace();
if (registry != null) {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
return sessionFactory;
}
public static void shutdown() {
if (registry != null) {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
7. Create the main App class and Run an Application
package net.javaguides.hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import net.javaguides.hibernate.entity.Account;
import net.javaguides.hibernate.util.HibernateUtil;
public class App {
public static void main(String[] args) {
Transaction transaction = null;
try (Session session = HibernateUtil.getSessionFactory().openSession()) {
// start a transaction
transaction = session.beginTransaction();
// save the account object
Account account = new Account();
account.setBalance(10000.0);
account.setInterestRate(10.0);
account.setOwner("Ramesh");
session.save(account);
// commit transaction
transaction.commit();
}
HibernateUtil.shutdown();
}
}
Since we used the JOINED inheritance strategy, all subclasses and superclass have their own table.
CREATE TABLE Account (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
PRIMARY KEY ( id )
)
CREATE TABLE CreditAccount (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
creditLimit NUMERIC(19, 2) ,
PRIMARY KEY ( id )
)
CREATE TABLE DebitAccount (
id BIGINT NOT NULL ,
balance NUMERIC(19, 2) ,
interestRate NUMERIC(19, 2) ,
owner VARCHAR(255) ,
overdraftFee NUMERIC(19, 2) ,
PRIMARY KEY ( id )
)
GitHub Repository
The complete source code of this article available on my GitHub Repository - https://github.com/RameshMF/Hibernate-ORM-Tutorials
Conclusion
In this article, we have looked into Hibernate/JPA table per class inheritance. You can check out below remaining three inheritance strategies:
You can learn more about Hibernate ORM Framework at Hibernate Tutorial
References
Free Spring Boot Tutorial | Full In-depth Course | Learn Spring Boot in 10 Hours
Watch this course on YouTube at Spring Boot Tutorial | Fee 10 Hours Full Course
Comments
Post a Comment