Hibernate Basics

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
  • Generate Id for Join Tables

Agenda (Cont.)

  • Proxy Object, Eager and Lazy Fetching
  • One to One Mapping
  • One to Many Mapping
  • Many to Many Mapping
  • Cascading 

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();
        session.close();
        sessionFactory.close();
    }
}

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);
        session.close();
        sessionFactory.close();
    }
}

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);
        session.close();
        sessionFactory.close();
    }
}

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);
        session.close();
        sessionFactory.close();
    }
}

Exercise 1

  • Create a class Author with instance variables firstName, lastName and age.
  • Perform CRUD operation for Author class.
  • Use hbm2ddl create to introduce Date of Birth for Author.
  • Use hbm2dll update to insert at least 4 records for Author.
  • Perform hbm2dll create-drop by closing session factory.

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: Hibernate selects the generation strategy based on the used dialect

 

  • IDENTITY: Hibernate relies on an auto-incremented database column to generate the primary key,

 

  • SEQUENCE: Hibernate requests the primary key value from a database sequence,

 

  • TABLE: Hibernate uses a database table to simulate a sequence.

 

Id Generation Stratergies

Exercise 2

  • Test Transient, Persistent and Detached state for Author Object.
  • Provide name Write to Author Table
  • Rename all the fields using column annotation.
  • Mark lastName as @Transient.
  • Use @Temporal for date of birth of Author.
  • Generate Id for Author Using IDENTITY and TABLE starategy.

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();
    }
}

Overriding attributes

import javax.persistence.*;

@Entity
public class Person{
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    String name;
    Integer age;
    @Embedded
    Address address;
    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "city", column = @Column(name = "CURRENT_CITY")),
            @AttributeOverride(name = "country", column = @Column(name = "CURRENT_COUNTRY"))
    })
    Address currentAddress;
}
import javax.persistence.Column;

public class Address {
    @Column(name = "HOME_CITY")
    String city;
    @Column(name = "HOME_COUNTRY")
    String country;
}

Exercise 3

  • Create a class Address for Author with instance variables streetNumber, location, State.
  • Use @Column to give column name to the instance variables of Address class.
  • Create instance variable of Address class inside Author class and save it as embedded object.
  • Now introduce one more Address type as currentAddress and Override attributes of Address class.

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

Configuring Collections and Adding Keys

@JoinTable annotatation is used to specify the name of the table and column which will be used to join collection table with the parent table.

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;
    @JoinTable(name = "employee_hobbies",
    joinColumns = @JoinColumn(name = "CUSTOM_JOIN_ID"))
    @ElementCollection
    Set<String> hobbies=new HashSet<String>();
}

Generate Id for Join Table

import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

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


@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @Temporal(TemporalType.DATE)
    Date dob;
    @JoinTable(name = "employee_hobbies",
    joinColumns = @JoinColumn(name = "CUSTOM_JOIN_ID"))
    @ElementCollection
    @GenericGenerator(name = "sequence-gen",strategy = "sequence")
    @CollectionId(columns = {@Column(name = "hobbies_id")},
    generator = "sequence-gen",type = @Type(type = "long"))
    Collection<String> hobbies=new HashSet<String>();
}

@CollectionId and @Generic Generator annotaions are use to Generate Id of a Join Table in the following way:

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

@Entity
@Table(name = "Employee")
public class Person {
    @Id @GeneratedValue(strategy =GenerationType.SEQUENCE )
    Integer id;
    String name;
    Integer age;
    @Temporal(TemporalType.DATE)
    Date dob;
    @JoinTable(name = "employee_hobbies",
        joinColumns = @JoinColumn(name = "CUSTOM_JOIN_ID"))
    @ElementCollection(fetch = FetchType.EAGER)
    Collection<String> hobbies=new ArrayList<String>();
}

Proxy Objects and Eager and Fetch Types

By Default Hibernate creates a proxy object and fills first level instance variables. To fetch Collection instance variables with object we need to set FetchType.Eager in @ElementCollection.

Exercise 4

  • Introduce a List of subjects for author.
  • Persist 3 subjects for each author.
  • Provide name to the JointTable and JoinColumn.
  • Generate Id For Join Table.
  • Experiment with Proxy and Eager Fetching.

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();
    }
}

Exercise 5

  • Create an Entity book with an instance variable bookName.
  • Implement One to One mapping between Author and Book.
  • Implement One to Many Mapping between Author and Book(Unidirectional, BiDirectional and without additional table ) and  implement cascade save.
  • Implement Many to Many Mapping between Author and Book.

Hibernate Basics

By Pulkit Pushkarna

Hibernate Basics

  • 1,415