🚀 Limited-Time Offer! Get 90% OFF on My Udemy Courses Grab the Deal 🎯

Hibernate/JPA Table Per Class Inheritance Example

🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.

▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube

▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube

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 6.1.7.Final
  • IDE - Eclipse
  • Maven 3.5.3
  • JavaSE 17
  • MySQL - 8.0.13

Development Steps

  1. Create a Simple Maven Project
  2. Project Directory Structure
  3. Add jar Dependencies to pom.xml
  4. Creating the JPA Entities
  5. Create a Hibernate configuration file - hibernate.cfg.xml
  6. Create a Hibernate utility class
  7. Create the Main class and Run an Application

1. Create a Simple Maven Project

Use the How to Create a Simple Maven Project in Eclipse article to create a 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.32</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.1.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>17</source> <target>17</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 jakarta.persistence.*; @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 jakarta.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 jakarta.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 hibernate.cfg.xml under the src/main/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> <!-- 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:
  1. Build the StandardServiceRegistry
  2. Build the Metadata
  3. 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 is 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

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare