Hibernate Bootcamp

Agenda

  • Understanding Hibernate
  • Setup
  • Hibernate xml configurations
  • hbm2ddl options
  • @Id and @Entity annotations
  • CRUD
  • Transient, Persistent and Detached states
  • Name Annotations
  • Generating Primary Key
  • Embedded types
  • Saving Collections
  • Configuring Collections and Adding Keys

Agenda (Cont.)

 

  • One to One Mapping
  • One to Many Mapping
  • Many to Many Mapping
  • Cascading 
  • Inheritance

What is Hibernate?

  • An ORM tool
  • Used in the data layer of applications
  • Implements JPA

The Problem solved by hibernate

User Class
Id
Name
Address
Phone
Date of Birth 
Id Name Address Phone Date of Birth

The Problem solved by hibernate (Cont.)

  • Mapping member variables to column
  • Mapping relationships
  • Handling data types
  • Managing changes to object state 

Set up with gradle

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile('org.hibernate:hibernate-core:5.2.6.Final')
    compile ('mysql:mysql-connector-java:5.1.6')
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--Database connection settings -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/poc</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password"/>

        <!--JDBC connection pool-->
        <property name="connection.pool_size">10</property>

        <!-- SQL Dialect-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!--echo all executed SQL-->
        <property name="show_sql">true</property>

        <!--drop or re-create database schema at startup-->
        <property name="hbm2ddl.auto">create</property>
        
        <!--Annotated entity class-->
        <mapping class="com.hibernate.demo.Person"/>
        
    </session-factory>
</hibernate-configuration>

hibernate.cfg.xml

hbm2ddl configurations

  • update: update the schema.
  • create: creates the schema, destroying previous data.
  • create-drop: drop the schema when the SessionFactory is closed explicitly, typically when the application is stopped.
  • none: Do not do anything. 

Special note about update for hbm2ddl auto

  • update won't modify existing table column definitions.

  • update will add a db column that doesn't already exist.

  • update will not delete a db column that is removed/no longer in your entity.

  • update will not modify a db column that has already been created.

@Id and @Entity



import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    Integer id;
    String name;
    Integer age;
}
  • @Entity : Marks the class as entity.
  • @Id  : Specifies primary key for the entity.

CRUD (Create)

  • Create a session factory
  • Create a session from session factory
  • Use the session to save model objects
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        Person person=new Person();
        person.setName("Hibernate");
        person.setAge(27);
        person.setId(2);
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        session.save(person);
        session.getTransaction().commit();
    }
}

CRUD (Read)

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        Person person=session.get(Person.class,1);
        session.getTransaction().commit();
        session.close();
        System.out.println(person);
    }
}

CRUD (Update)

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        Person person=session.get(Person.class,1);
        person.setName("Updated Name");
        session.update(person);
        session.getTransaction().commit();
        session.close();
        System.out.println(person);
    }
}

CRUD (Delete)

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        Person person=session.get(Person.class,1);
        session.delete(person);
        session.getTransaction().commit();
        session.close();
        System.out.println(person);
    }
}

Transient, Persistent and Detached states

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        Person person=new Person();
        //Transient state
        person.setName("Hibernate");
        person.setAge(23);

        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        //Persistent state
        session.save(person);
        person.setName("Updated");
        
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();

        //Detached state
        person.setName("Updated in detached");

    }
}

Name Annotations

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity(name = "Employee")
public class Person {
    @Id
    Integer id;
    @Column(name = "First_Name")
    String name;
    Integer age;
}
  • Name property can be used with @Entity and @Column annotation to specify the name of table and column.
  • @Id and @Column annotations can be used with getters also.

More Annotations

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "Employee")
public class Person {
    @Id
    Integer id;
    @Column(name = "First_Name")
    String name;
    @Transient
    Integer age;
    @Temporal(TemporalType.DATE)
    Date dob;
}
  • @Table annotation is used to store specify the name of the table for entity.
  • @Transient is used to ignore the field of an entity while persisting it into a database.
  • @Temporal annotation is used with Date types to specify what should be saved i.e DATE, TIME or TIMESTAMP

Automatically generate primary key value

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @Temporal(TemporalType.DATE)
    Date dob;
}
  • @GenerateValue annotation can be used to generate id for objects while persistence.
  • AUTO (default): Tells Doctrine to pick the strategy that is preferred by the used database platform. The preferred strategies are IDENTITY for MySQL, SQLite and MsSQL and SEQUENCE for Oracle and PostgreSQL. This strategy provides full portability.
  • SEQUENCE: Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full portability. Sequences are supported by Oracle and PostgreSql.
  • IDENTITY: Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row. This strategy does currently not provide full portability and is supported by the following platforms:

         MySQL/SQLite => AUTO_INCREMENT

        MSSQL => IDENTITY

        PostgreSQL => SERIAL

Id Generation Stratergies

  • TABLE: Tells Doctrine to use a separate table for ID generation. This strategy provides full portability.

Id Generation Stratergies (cont.)

Embedded Type

import javax.persistence.*;

@Entity
public class Person{
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    String name;
    Integer age;
    @Embedded
    Address address;
}

For embedded object we can use @Embedded annotation for the Reference type instance variable

import javax.persistence.Embeddable;

@Embeddable
public class Address {
    String city;
    String country;
}

Optionally we can also place @Embeddable on the class of the reference type instance variable

Embedded type (Cont.)

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        Person person=new Person();
        person.setName("Hibernate");
        person.setAge(23);
        Address address=new Address();
        address.setCity("Delhi");
        address.setCountry("India");
        person.setAddress(address);
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        session.save(person);
        session.getTransaction().commit();
        session.close();
    }
}

Saving Collections

import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @Temporal(TemporalType.DATE)
    Date dob;
    @ElementCollection
    Set<String> hobbies=new HashSet<String>();
}
  • @ElementCollection annotation is used to persist collections in Hibernate entities

One to One mapping

import javax.persistence.*;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @OneToOne
    @JoinColumn(name = "Vehicle_join_column")
    Vehicle vehicle;
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Vehicle {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    Integer vehicleId;
    String vehicleName;
}

One to One mapping (Cont.)

Person person=new Person();
person.setName("Hibernate");
person.setAge(27);
person.setId(1);
Vehicle vehicle=new Vehicle();
vehicle.setVehicleName("Car");
person.setVehicle(vehicle);
SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(person);
session.save(vehicle);
session.getTransaction().commit();
session.close();

One to Many (Unidirectional)

import javax.persistence.*;
import java.util.Collection;
import java.util.HashSet;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @OneToMany
    @JoinTable(joinColumns = @JoinColumn(name="USER_ID")
            ,inverseJoinColumns = @JoinColumn(name = "VEHICAL_ID"))
    Collection<Vehicle> vehicle= new HashSet<Vehicle>();
}
import javax.persistence.*;

@Entity
public class Vehicle {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    Integer vehicleId;
    String vehicleName;
}

One to Many (Unidirectional) Cont.

Person person=new Person();
person.setName("Hibernate");
person.setAge(27);
person.setId(1);
Vehicle vehicle=new Vehicle();
vehicle.setVehicleName("Car");
Vehicle vehicle2=new Vehicle();
vehicle2.setVehicleName("Bike");
person.getVehicle().add(vehicle);
person.getVehicle().add(vehicle2);
SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(person);
session.save(vehicle);
session.save(vehicle2);
session.getTransaction().commit();
session.close();

One to Many (Bidirectional)

import javax.persistence.*;
import java.util.Collection;
import java.util.HashSet;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @OneToMany
    @JoinTable(joinColumns = @JoinColumn(name="USER_ID")
            ,inverseJoinColumns = @JoinColumn(name = "VEHICAL_ID"))
    Collection<Vehicle> vehicle= new HashSet<Vehicle>();
}
import javax.persistence.*;

@Entity
public class Vehicle {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    Integer vehicleId;
    String vehicleName;
    @ManyToOne
    Person person;
}
Person person=new Person();
person.setName("Hibernate");
person.setAge(27);
person.setId(1);
Vehicle vehicle=new Vehicle();
vehicle.setVehicleName("Car");
vehicle.setPerson(person);
Vehicle vehicle2=new Vehicle();
vehicle2.setPerson(person);
vehicle2.setVehicleName("Bike");
person.getVehicle().add(vehicle);
person.getVehicle().add(vehicle2);
SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(person);
session.save(vehicle);
session.save(vehicle2);
session.getTransaction().commit();
session.close();

One to Many (Bidirectional) Cont.

One to Many without additional table 

import javax.persistence.*;
import java.util.Collection;
import java.util.HashSet;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @OneToMany(mappedBy = "person")
    Collection<Vehicle> vehicle= new HashSet<Vehicle>();
}
import javax.persistence.*;

@Entity
public class Vehicle {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    Integer vehicleId;
    String vehicleName;
    @ManyToOne
    Person person;
}

Many to Many 

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @ManyToMany
    List<Vehicle> vehicle= new ArrayList<Vehicle>();
}
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Vehicle {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    Integer vehicleId;
    String vehicleName;
    @ManyToMany(mappedBy = "vehicle")
    List<Person> personList = new ArrayList<Person>();
}

Cascade Type

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Person{
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    Integer id;
    String name;
    Integer age;
    @OneToMany(cascade = CascadeType.PERSIST)
    List<Vehicle> listOfVehicles=new ArrayList<Vehicle>();
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Vehicle {
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    Integer vehicleId;
    String vehicleName;
}

Cascade Type (Cont.)

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Application {
    public static void main(String[] args) {
        Person person=new Person();
        person.setName("Hibernate");
        person.setAge(23);
        Vehicle vehicle=new Vehicle();
        vehicle.setVehicleName("Car");
        person.getListOfVehicles().add(vehicle);
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
        session.beginTransaction();
        session.persist(person);
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }
}

Inheritance

Hibernate provides several strategies to leverage this object-oriented trait onto domain model entities.

MappedSuperclass

When using MappedSuperclass, the inheritance is visible in the domain model only and each database table contains both the base class and the subclass properties.

import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public class Account {
    @Id
    private Integer id;
    private String owner;
    private Integer balance;
    private Integer interestRate;

    //getters and setters    
}
import javax.persistence.Entity;

@Entity
public class DebitAccount extends Account{

    private Integer overdraftFee;

    //getter and setter
}


DebitAccount debitAccount=new DebitAccount();
debitAccount.setOwner("Peter");
debitAccount.setBalance(23000);
debitAccount.setInterestRate(23);
debitAccount.setId(2);
debitAccount.setOverdraftFee(2300);
session.save(debitAccount);

Single Table

The single table inheritance strategy maps all subclasses to only one database table. Each subclass declares its own persistent properties.

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Account {
    @Id
    private Integer id;
    private String owner;
    private Integer balance;
    private Integer interestRate;
}
import javax.persistence.Entity;

@Entity
public class DebitAccount extends Account{

    private Integer overdraftFee;

    // getter and setter
}

Joined Table

Each subclass can also be mapped to its own table. This is also called table-per-subclass mapping strategy. An inherited state is retrieved by joining with the table of the superclass.

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Account {
    @Id
    private Integer id;
    private String owner;
    private Integer balance;
    private Integer interestRate;
}
import javax.persistence.Entity;

@Entity
public class DebitAccount extends Account{

    private Integer overdraftFee;

    // getter and setter
}

Table per class

This is called the table-per-concrete-class strategy. Each table defines all persistent states of the class, including the inherited state.

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Account {
    @Id
    private Integer id;
    private String owner;
    private Integer balance;
    private Integer interestRate;
}
import javax.persistence.Entity;

@Entity
public class DebitAccount extends Account{

    private Integer overdraftFee;

    // getter and setter
}

Hibernate Bootcamp

By Pulkit Pushkarna

Hibernate Bootcamp

  • 1,770