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
- 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 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:
- 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 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
Post a Comment
Leave Comment