Friday 23 December 2022

Hibernate 6: working with entity identifiers

Entity identifiers are used to uniquely identify a row in a table. Hibernate and JPA (Jakarta Persistence API), assumes following rules must be followed by the identifier.

 

a.   Identifier must be unique in a table.

b.   Identifier must not be null. If you use a composite key as an identifier, then no other part can be null.

c.    Once a value assigned to identifier property, the value must not be changed on any circumstances.

 

Types of identifiers

An identifier can be

a.   Simple

b.   Composite

 

Let’s discuss about simple identifier in this post.

 

Simple identifiers

Simple identifiers are defined by decorating a single basic attribute with @Id annotation.

 

Example

@Entity
@Table(name = "employees")
public class Employee {
      @Id
      private Integer id;

      ..........
      ..........
}

As per Jakarta Persistence API, following types can be used as identifiers.

 

a.   Any Java primitive, primitive wrapper type

b.   java.lang.String

c.    java.util.Date (TemporalType#DATE)

d.   java.sql.Date

e.   java.math.BigDecimal

f.     java.math.BigInteger

 

Apart from this Hibernate support UUID as a primary key, which I covered in my earlier posts.

 

Follow below step-by-step procedure to build a working application.

 

Step 1: Create new maven project ‘hibernate-simple-identifier-demo’.

 

Step 2: Update pom.xml with maven dependencies.

 

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.sample.app</groupId>
      <artifactId>hibernate-simple-identifier-demo</artifactId>
      <version>1</version>

      <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

            <java.version>15</java.version>
            <maven.compiler.source>${java.version}</maven.compiler.source>
            <maven.compiler.target>${java.version}</maven.compiler.target>

      </properties>

      <dependencies>
            <dependency>
                  <groupId>com.h2database</groupId>
                  <artifactId>h2</artifactId>
                  <version>2.1.214</version>
            </dependency>

            <dependency>
                  <groupId>org.hibernate</groupId>
                  <artifactId>hibernate-core</artifactId>
                  <version>6.1.2.Final</version>
            </dependency>

      </dependencies>
</project>

Step 3: Define Employee entity class.

 

Employee.java

package com.sample.app.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {
      @Id
      private Integer id;

      private String name;

      public Employee(Integer id, String name) {
            this.id = id;
            this.name = name;
      }

      public Integer getId() {
            return id;
      }

      public void setId(Integer id) {
            this.id = id;
      }

      public String getName() {
            return name;
      }

      public void setName(String name) {
            this.name = name;
      }

      @Override
      public String toString() {
            return "Employee [id=" + id + ", name=" + name + "]";
      }

}

Step 4: Create hibernate.cfg.xml file under src/main/resources folder.

 

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!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">org.h2.Driver</property>
            <property name="connection.url">jdbc:h2:mem:test</property>
            <property name="connection.username">admin</property>
            <property name="connection.password">admin</property>
            <property name="connection.pool_size">1</property>

            <property name="dialect">org.hibernate.dialect.H2Dialect</property>
            <!-- Echo the SQL to stdout -->
            <property name="show_sql">true</property>
            <property name="format_sql">true</property>
            <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">2</property>
            <property name="hibernate.dbcp.maxTotal">10</property>
            <property name="hibernate.dbcp.maxIdle">5</property>
            <property name="hibernate.dbcp.minIdle">3</property>
            <property name="hibernate.dbcp.maxWaitMillis">-1</property>

            <!-- mappings for annotated classes -->
            <mapping class="com.sample.app.entity.Employee" />

      </session-factory>

</hibernate-configuration>

Step 5: Define main application class.

 

App.java

package com.sample.app;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
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;

import com.sample.app.entity.Employee;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;

public class App {
      private static SessionFactory sessionFactory = buildSessionFactory();

      private static <T> List<T> loadAllData(Class<T> clazz, Session session) {
            final CriteriaBuilder builder = session.getCriteriaBuilder();
            final CriteriaQuery<T> criteria = builder.createQuery(clazz);
            criteria.from(clazz);
            return session.createQuery(criteria).getResultList();
      }

      private static SessionFactory buildSessionFactory() {
            try {
                  if (sessionFactory == null) {
                        StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
                                    .configure("hibernate.cfg.xml").build();

                        Metadata metaData = new MetadataSources(standardRegistry).getMetadataBuilder().build();

                        sessionFactory = metaData.getSessionFactoryBuilder().build();
                  }
                  return sessionFactory;
            } catch (Throwable ex) {
                  throw new ExceptionInInitializerError(ex);
            }
      }

      public static void main(String args[]) {

            Map<String, Object> config = new HashMap<>();
            config.put("maxThreads", 10);
            config.put("storagePath", "/Users/krishna/my-docs");

            Employee emp1 = new Employee(1, "Krishna");
            Employee emp2 = new Employee(2, "Ram");

            try (Session session = sessionFactory.openSession()) {
                  session.beginTransaction();
                  session.persist(emp1);
                  session.persist(emp2);
                  session.flush();
                  session.getTransaction().commit();

                  List<Employee> emps = loadAllData(Employee.class, session);
                  for (Employee emp : emps) {
                        System.out.println(emp);

                  }

            }

      }
}

Total project structure looks like below.




Run App.java, you will see below messages in the console.

Aug 22, 2022 3:57:21 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.1.2.Final
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.h2.Driver
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:h2:mem:test]
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {password=****, user=admin}
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 1 (min=1)
Aug 22, 2022 3:57:22 PM org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl logSelectedDialect
INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Aug 22, 2022 3:57:22 PM org.hibernate.metamodel.internal.EntityInstantiatorPojoStandard resolveConstructor
INFO: HHH000182: No default (no-argument) constructor for class: com.sample.app.entity.Employee (class must be instantiated by Interceptor)
Hibernate: 
    
    drop table if exists employees cascade 
Aug 22, 2022 3:57:22 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@7593ea79] 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 employees (
       id integer not null,
        name varchar(255),
        primary key (id)
    )
Aug 22, 2022 3:57:22 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@2ab26378] 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: 
    insert 
    into
        employees
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        employees
        (name, id) 
    values
        (?, ?)
Hibernate: 
    select
        e1_0.id,
        e1_0.name 
    from
        employees e1_0
Employee [id=1, name=Krishna]
Employee [id=2, name=Ram]

You can download this application from this link.


 

Previous                                                    Next                                                    Home

No comments:

Post a Comment