Hibernate Framework Architecture and Basics
Hibernate Hello World Tutorial
Hibernate XML Configuration Example
Hibernate Java Configuration Example
Hibernate Transaction Management
Hibernate/JPA - Primary Key Generation Strategies
JPA and Hibernate Cascade Types
Hibernate - Save an Entity Example
Hibernate - Persist an Entity Example
Hibernate - saveOrUpdate() Method Example
Hibernate - get(), load() and byId() Method
Hibernate - merge() Example
Hibernate - Delete or Remove an Entity Example
Hibernate - load() Method Example
Hibernate Session.clear() Method Example
Hibernate One to One Mapping
Hibernate One to Many Mapping
Hibernate Many to Many Annotation
Hibernate One to Many CRUD Example
Hibernate One to One CRUD Example
Hibernate Inheritance Mapping
Hibernate Query Language
Hibernate CRUD Operations Example
Hibernate Session Interface Methods
JSP Servlet Hibernate CRUD Example
Hibernate Registration Form Example
Login Form using JSP + Servlet + Hibernate + MySQL
More .........
In this tutorial, we will learn how to implement Hibernate one to one mapping with a shared primary key using @PrimaryKeyJoinColumn annotation.
Hibernate will ensure that it will use a common primary key value in both the tables. This way primary key of Employee can safely be assumed the primary key of Account also.
Employee JPA Entity
Let's create an Employee JPA entity and the account field is annotated with @PrimaryKeyJoinColumn annotation:
package net.javaguides.hibernate.entity.sharedPrimaryKey;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity(name = "SharedPrimaryKeyEmployeeEntity")
@Table(name = "Employee", uniqueConstraints = {
@UniqueConstraint(columnNames = "ID"),
@UniqueConstraint(columnNames = "EMAIL")
})
public class Employee implements Serializable {
private static final long serialVersionUID = -1798070786993154676 L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private Integer employeeId;
@Column(name = "EMAIL", unique = true, nullable = false, length = 100)
private String email;
@Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
private String firstName;
@Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
private String lastName;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Account account;
public Integer getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
Account JPA Entity
On the Account JPA entity side, it will remain dependent on the owner entity (Employee) for the mapping.
package net.javaguides.hibernate.entity.sharedPrimaryKey;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity(name = "SharedPrimaryKeyAccountEntity")
@Table(name = "ACCOUNT", uniqueConstraints = {
@UniqueConstraint(columnNames = "ID")
})
public class Account implements Serializable {
private static final long serialVersionUID = -6790693372846798580 L;
@Id
@Column(name = "ID", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = @Parameter(name = "property", value = "employee"))
private Integer accountId;
@Column(name = "ACC_NUMBER", unique = true, nullable = false, length = 100)
private String accountNumber;
@OneToOne(mappedBy = "account", cascade = CascadeType.ALL)
private Employee employee;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
}
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 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/java_demo?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.foreignKeyAsso.Employee"/><mapping class="net.javaguides.hibernate.entity.foreignKeyAsso.Account"/> -->
<mapping class="net.javaguides.hibernate.entity.sharedPrimaryKey.Employee"/>
<mapping class="net.javaguides.hibernate.entity.sharedPrimaryKey.Account"/>
<!-- <mapping class="net.javaguides.hibernate.entity.joinTable.Employee"/><mapping class="net.javaguides.hibernate.entity.joinTable.Account"/> -->
</session-factory>
</hibernate-configuration>
Hibernate Utility Class - HibernateUtil.java
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 and Session is a single-threaded object.
Let's create a HibernateUtil class to configure singleton SessionFactory and use it throughout the application. 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);
}
}
}
Create the Test class and Run an Application
package net.javaguides.hibernate.test;
import org.hibernate.Session;
import net.javaguides.hibernate.entity.sharedPrimaryKey.Account;
import net.javaguides.hibernate.entity.sharedPrimaryKey.Employee;
import net.javaguides.hibernate.util.HibernateUtil;
public class TestSharedPrimaryKey {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Account account = new Account();
account.setAccountNumber("123-345-65454");
//Add new Employee object
Employee emp = new Employee();
emp.setEmail("demo-user@mail.com");
emp.setFirstName("demo");
emp.setLastName("user");
emp.setAccount(account);
account.setEmployee(emp);
//Save Employee
session.save(emp);
session.getTransaction().commit();
HibernateUtil.shutdown();
}
}
Output
The above application will generate the following output:
Dec 27, 2019 7:14:29 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.3.7.Final}
Dec 27, 2019 7:14:29 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Dec 27, 2019 7:14:29 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
Dec 27, 2019 7:14:30 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
Dec 27, 2019 7:14:30 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [com.mysql.cj.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/java_demo?useSSL=false]
Dec 27, 2019 7:14:30 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=root, password=****}
Dec 27, 2019 7:14:30 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Dec 27, 2019 7:14:30 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 1 (min=1)
Dec 27, 2019 7:14:30 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: drop table if exists ACCOUNT
Dec 27, 2019 7:14:31 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@10b3df93] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: drop table if exists Employee
Hibernate: create table ACCOUNT (ID integer not null, ACC_NUMBER varchar(100) not null, primary key (ID)) engine=MyISAM
Dec 27, 2019 7:14:31 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@12f3afb5] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table Employee (ID integer not null auto_increment, EMAIL varchar(100) not null, FIRST_NAME varchar(100) not null, LAST_NAME varchar(100) not null, primary key (ID)) engine=MyISAM
Hibernate: alter table ACCOUNT add constraint UK_nsa1j7vica4ow9xhhkudukb3j unique (ACC_NUMBER)
Hibernate: alter table Employee add constraint UK_ardf0f11mfa6tujs3hflthwdv unique (EMAIL)
Dec 27, 2019 7:14:32 PM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@7bd69e82'
Hibernate: insert into Employee (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into ACCOUNT (ACC_NUMBER, ID) values (?, ?)
Dec 27, 2019 7:14:32 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/java_demo?useSSL=false]
Comments
Post a Comment
Leave Comment