Hibernate Object Relational Mapping Framework - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Saturday, January 13, 2018

Hibernate Object Relational Mapping Framework

Hibernate

Hibernate is an object relational mapping framework for Java programming language. It provides mapping between object-oriented domain model to a relational database. Hibernate handles object-relational impedance mismatch problem.

Hibernate allows us to specify the configuration to use to connect with database and to specify the way Java objects should be mapped to the tables in their database.

Hibernate's primary feature is mapping from Java classes to database tables, and mapping from Java data types to SQL data types. Hibernate also provides data query and retrieval facilities. It generates SQL calls and relieves the developer from the manual handling and object conversion of the result set.

Hibernate is free software that is distributed under the GNU Lesser General Public License 2.1.

Bookstore application with hibernate

In previous post we have discussed the bookstore application object-relational mapping with relational database using JDBC. In this post we will discuss the same bookstore application using the Hibernate ORM framework. Let's see the bookstore application object model and relational model mapping. Hibernate will do everything for us.

Bookstore application object-relational mapping with Hibernate

Project dependencies

This application is a gradle based application.

group 'com.walking.techie'
version '1.0'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'org.projectlombok:lombok:1.16.18'
    compile 'org.hibernate:hibernate-core:5.2.12.Final'
    runtime group: 'mysql', name: 'mysql-connector-java', version: '5.1.40'
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

Java model classes

Bookstore application has three java classes Book, Publisher, and Chapter. These are simple java class called Plain Old Java Object.

ChapterPrimaryKey is a embeddable value type that is embedded into Chapter class. This is used to create composite key.

package com.walking.techie.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

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

@Entity
@Table(name = "BOOK")
@Getter
@Setter
@NoArgsConstructor
@ToString
public class Book {
    @Id
    @Column(name = "ISBN")
    private String isbn;
    @Column(name = "BOOK_NAME")
    private String name;

    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "PUBLISHER_CODE")
    private Publisher publisher;

    @OneToMany(mappedBy = "chapterPrimaryKey.book", cascade = CascadeType.PERSIST)
    private List<Chapter> chapters;

    public Book(String isbn, String name, Publisher publisher, List<Chapter> chapters) {
        this.isbn = isbn;
        this.name = name;
        this.publisher = publisher;
        this.chapters = chapters;
    }
}
package com.walking.techie.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;

@Entity
@Table(name = "PUBLISHER")
@Getter
@Setter
@NoArgsConstructor
@ToString(exclude = {"book"})
public class Publisher {
    @Id
    @Column(name = "CODE")
    private String code;

    @Column(name = "PUBLISHER_NAME")
    private String name;

    @OneToOne(mappedBy = "publisher")
    private Book book;

    public Publisher(String code, String name) {
        this.code = code;
        this.name = name;
    }
}
package com.walking.techie.model;

import com.walking.techie.ChapterPrimaryKey;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "CHAPTER")
@Getter
@Setter
@NoArgsConstructor
@ToString
public class Chapter {
    @EmbeddedId
    private ChapterPrimaryKey chapterPrimaryKey;

    @Column(name = "TITLE")
    private String title;

    public Chapter(String title, ChapterPrimaryKey chapterPrimaryKey) {
        this.title = title;
        this.chapterPrimaryKey = chapterPrimaryKey;
    }
}
package com.walking.techie.model;

import com.walking.techie.model.Book;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;

@Embeddable
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude = {"book"})
public class ChapterPrimaryKey implements Serializable {
    @Column(name = "CHAPTER_NUM")
    private Integer chapterNumber;

    @ManyToOne
    @JoinColumn(name = "BOOK_ISBN")
    private Book book;
}

Bookstore application relational model

We are using MySQL database to store the object graph of bookstore application.

CREATE DATABASE bookstore;
<?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>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/bookstore?useSSL=false</property>
        <property name="connection.username">root</property>
        <property name="connection.password">santosh</property>
        <property name="hbm2ddl.auto">update</property>

        <!-- SQL Dialect -->
        <property name="dialect">org.hibernate.dialect.MariaDBDialect</property>
        <!--Echo all executed SQL query to console-->
        <property name="show_sql">true</property>

        <mapping class="com.walking.techie.model.Book"/>
        <mapping class="com.walking.techie.model.Publisher"/>
        <mapping class="com.walking.techie.model.Chapter"/>

    </session-factory>
</hibernate-configuration>

Tables created in bookstore database and their relationship as below diagram. In CHAPTER table both BOOK_ISBN, and CHAPTER_NUM defined as primary key that together will uniquely identify a chapter.

Database connection

Here, creating database connection with MySQL using hibernate configuration file.

package com.walking.techie.utils;


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 {

    public static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
                    .configure("hibernate.cfg.xml").build();
            Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().build();
            return metadata.getSessionFactoryBuilder().build();
        } catch (Exception ex) {
            System.err.println("Initial session factory creation failed: " + ex.getMessage());
            throw new ExceptionInInitializerError();
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Persist Object Graph in Relational Database

Book Application client

package com.walking.techie;

import com.walking.techie.model.Book;
import com.walking.techie.model.Chapter;
import com.walking.techie.model.ChapterPrimaryKey;
import com.walking.techie.model.Publisher;
import com.walking.techie.utils.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import java.util.LinkedList;
import java.util.List;

public class BookStoreClient {
    public static void main(String[] args) {
        // All Book information
        List<Chapter> chapters = new LinkedList<>();
        Publisher publisher = new Publisher("TECH", "Java Publications");

        Book book = new Book("123456789", "Java Persistence with Hibernate", publisher, chapters);
        ChapterPrimaryKey cpk1 = new ChapterPrimaryKey(1, book);
        ChapterPrimaryKey cpk2 = new ChapterPrimaryKey(2, book);
        Chapter chapter1 = new Chapter("Introduction of Hibernate", cpk1);
        Chapter chapter2 = new Chapter("Introduction of JPA and Hibernate", cpk2);

        chapters.add(chapter1);
        chapters.add(chapter2);

        List<Chapter> chapters1 = new LinkedList<>();
        Publisher publisher1 = new Publisher("MANN", "Java Publications");
        Book book1 = new Book("123456799", "Java Persistence with Hibernate", publisher1, chapters1);
        ChapterPrimaryKey cpk3 = new ChapterPrimaryKey(1, book1);
        ChapterPrimaryKey cpk4 = new ChapterPrimaryKey(2, book1);
        Chapter chapter3 = new Chapter("Introduction of Hibernate", cpk3);
        Chapter chapter4 = new Chapter("Introduction of JPA and Hibernate", cpk4);

        chapters1.add(chapter3);
        chapters1.add(chapter4);
        SessionFactory sessionFactory = null;
        try {
            sessionFactory = HibernateUtil.getSessionFactory();
            Session session = sessionFactory.openSession();
            Transaction transaction = session.beginTransaction();

            // save book object graph in DB
            session.persist(book);
            session.persist(book1);

            // retrieve Book object graph from DB based on ISBN
            book = session.get(Book.class, "123456789");
            // print book information on console
            System.out.println(book);
            book = session.get(Book.class, "123456799");
            // print book information on console
            System.out.println(book);
            transaction.commit();
            session.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sessionFactory != null)
                sessionFactory.close();
        }

    }
}

Once you run the client Book object graph will save into DB and fetch the saved object graph using ISBN of book. Output will print on console like below.

Jan 09, 2018 11:14:37 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {5.2.12.Final}
Jan 09, 2018 11:14:37 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Jan 09, 2018 11:14:37 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
Jan 09, 2018 11:14:38 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
Jan 09, 2018 11:14:38 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/bookstore?useSSL=false]
Jan 09, 2018 11:14:38 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {user=root, password=****}
Jan 09, 2018 11:14:38 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Jan 09, 2018 11:14:38 PM org.hibernate.engine.jdbc.connections.internal.PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
Jan 09, 2018 11:14:38 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MariaDBDialect
Jan 09, 2018 11:14:39 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@68044f4] 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 BOOK (ISBN varchar(255) not null, BOOK_NAME varchar(255), PUBLISHER_CODE varchar(255), primary key (ISBN)) engine=InnoDB
Hibernate: create table CHAPTER (CHAPTER_NUM integer not null, TITLE varchar(255), BOOK_ISBN varchar(255) not null, primary key (BOOK_ISBN, CHAPTER_NUM)) engine=InnoDB
Hibernate: create table PUBLISHER (CODE varchar(255) not null, PUBLISHER_NAME varchar(255), primary key (CODE)) engine=InnoDB
Hibernate: alter table BOOK add constraint FKqvgq79wneshq59abs6f5tyjjl foreign key (PUBLISHER_CODE) references PUBLISHER (CODE)
Hibernate: alter table CHAPTER add constraint FKsullkfioeysqbf02q2e6keumx foreign key (BOOK_ISBN) references BOOK (ISBN)
Book(isbn=123456789, name=Java Persistence with Hibernate, publisher=Publisher(code=TECH, name=Java Publications), chapters=[Chapter(chapterPrimaryKey=ChapterPrimaryKey(chapterNumber=1), title=Introduction of Hibernate), Chapter(chapterPrimaryKey=ChapterPrimaryKey(chapterNumber=2), title=Introduction of JPA and Hibernate)])
Book(isbn=123456799, name=Java Persistence with Hibernate, publisher=Publisher(code=MANN, name=Java Publications), chapters=[Chapter(chapterPrimaryKey=ChapterPrimaryKey(chapterNumber=1), title=Introduction of Hibernate), Chapter(chapterPrimaryKey=ChapterPrimaryKey(chapterNumber=2), title=Introduction of JPA and Hibernate)])
Hibernate: insert into PUBLISHER (PUBLISHER_NAME, CODE) values (?, ?)
Hibernate: insert into BOOK (BOOK_NAME, PUBLISHER_CODE, ISBN) values (?, ?, ?)
Hibernate: insert into CHAPTER (TITLE, BOOK_ISBN, CHAPTER_NUM) values (?, ?, ?)
Hibernate: insert into CHAPTER (TITLE, BOOK_ISBN, CHAPTER_NUM) values (?, ?, ?)
Hibernate: insert into PUBLISHER (PUBLISHER_NAME, CODE) values (?, ?)
Hibernate: insert into BOOK (BOOK_NAME, PUBLISHER_CODE, ISBN) values (?, ?, ?)
Hibernate: insert into CHAPTER (TITLE, BOOK_ISBN, CHAPTER_NUM) values (?, ?, ?)
Hibernate: insert into CHAPTER (TITLE, BOOK_ISBN, CHAPTER_NUM) values (?, ?, ?)
Jan 09, 2018 11:14:42 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/bookstore?useSSL=false]

No comments :

Post a Comment