Click here to Skip to main content
14,971,209 members
Articles / Programming Languages / Java
Article
Posted 18 Dec 2017

Tagged as

Stats

7.5K views
43 downloads
3 bookmarked

A Note on Spring Boot - 3

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
18 Dec 2017CPOL6 min read
This is a note on Spring Boot and Hibernate

Introduction

This is a note on Spring Boot and Hibernate.

Background

This is a note on Spring Boot and Hibernate. The attached Maven project is a Spring Boot application packed as an executable JAR.

  • If you are not an expert on Spring Boot, I will recommend you to take a look at my earlier note "A Note on Spring Boot - 1" to see how to pack a web application into a JAR file;
  • Because I am using a Linux Mint computer, I will use MySQL as the database server for the example.

Install MySQL & MySQL Workbench

The installation of MySQL server is a simple task on a Linux Mint computer. Click on "menu" and search for "Software Manager", you can find and launch the "Software Manager".

Image 1

If you search for "mysql", you can find both the "mysql-server" and "mysql-workbench". You can then follow the instructions to install both of them. Please make sure to remember the password that you choose for the "root" user, you will need it to access the MySQL server. The versions of the "mysql-server" and "mysql-workbench" may not be the most recent, but they should be close enough to the most recent published versions.

Image 2

By default, MySQL server starts when the computer starts. But on a development computer, you may not want to start it all the time. You may want to start it manually when you need it. You can find the "/etc/int/mysql.conf" file and comment out the line "start on runlevel ..." by "#". To manually start the MySQL server, you can issue the following command.

sudo service mysql start

You can stop it by the following command.

sudo service mysql stop

You can check if the MySQL server is running by the following command.

sudo service mysql status

With the MySQL server started, you can launch the MySQL Workbench to connect to it.

Image 3

You can issue the following SQL script through the MySQL Workbench to create the database table and add some data.

SQL
DROP DATABASE IF EXISTS experimentA;
CREATE DATABASE experimentA;
    
USE experimentA;
    
CREATE TABLE Student (
  Id int(11) NOT NULL AUTO_INCREMENT,
  Name varchar(100) COLLATE latin1_general_ci NOT NULL,
  Score int(11) NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=1
    DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
    
INSERT INTO Student (Name, Score)
    VALUES ('Song Li', 25);
INSERT INTO experimentA.Student (Name, Score)
    VALUES ('Donald Trump', 100);
    
SELECT * FROM Student;

Upon a successful run of the SQL script, you should have a table named [Student]. We will use this table to try Hibernate in Spring Boot.

Image 4

The Example - Spring Boot + Hibernate

Image 5

The attached is a Maven application for a JAR packaged Spring Boot application.

  • This note is intended for Spring Boot + Hibernate, so I will not spend a lot of time on Spring Boot alone;
  • If you are not an expert on Spring Boot, I will recommend you to take a look at my earlier note "A Note on Spring Boot - 1" to see how to pack a web application into a JAR file; 

Since it is a Maven project, let us first take a look at the "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 
    http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.song.example</groupId>
    <artifactId>spring-boot-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <properties>
        <spring-boot.version>1.5.7.RELEASE</spring-boot.version>
        <hibernate.version>5.2.12.Final</hibernate.version>
        <mysql.connector.version>6.0.6</mysql.connector.version>
    </properties>
    
    <dependencies>                 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.connector.version}</version>
        </dependency>
    </dependencies>
      
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration><source>1.8</source><target>1.8</target></configuration>
            </plugin>
            
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                  <execution>
                    <goals><goal>repackage</goal></goals>
                    <configuration>
                        <finalName>${artifactId}-${version}</finalName>
                          <mainClass>${start-class}</mainClass>
                          <addResources>true</addResources>
                    </configuration>
                  </execution>
                </executions>
            </plugin>
            
        </plugins>
    </build>
</project>
  • The dependency "spring-boot-starter-web" is needed for a Spring Boot application;
  • The dependency "hibernate-entitymanager" is needed when we use Hibernate. It is the top level Maven package for Hibernate. By including this package, we effectively declared all the packages needed for Hibernate.
  • The dependency "mysql-connector-java" is the JDBC driver to connect to the MySQL database;
  • The build plug-in "spring-boot-maven-plugin" is required to package the application to an executable JAR file.

In order to access the [Student] table in the MySQL database, we need to add an "@Entity" class, which is implemented in the "Student.java" file.

package com.song.hibernate.entities;
    
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
    
@Entity
@Table(name = "Student")
public class Student implements java.io.Serializable {
    private static final long serialVersionUID = -2724306148955297613L;
    
    private Integer id;
    private String name;
    private Integer score;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "Id")
    public Integer getId() { return this.id; }
    public void setId(Integer id) { this.id = id; }
    
    @Column(name = "Name", length = 100)
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }
    
    @Column(name = "Score")
    public Integer getScore() { return this.score; }
    public void setScore(Integer score) { this.score = score; }
    
}

In order to create a Hibernate "SessionFactory", we will need to add the "hibernate.cfg.xml" in the "src/main/resources" directory. The typical use of the Hibernate "SessionFactory" in an application is to make it a singleton. This singleton object manages all the "Sessions" that makes the database operations.

  • A "SessionFactory" is thread safe. We can allow multiple threads to access it;
  • A "Session" is not thread safe. We need to make sure only one thread can use it. When we finish the database operation, we need to close the session.
<?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>
        <property name="connection.driver_class">
            com.mysql.cj.jdbc.Driver
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost/experimentA
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password">password</property>
    
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
    
        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">
            org.hibernate.cache.NoCacheProvider
        </property>
    
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
    
    <mapping class="com.song.hibernate.entities.Student" />
    </session-factory>
</hibernate-configuration>
  • The "hibernate.cfg.xml" file configures how Hibernate communicate with the database server;
  • The "<mappping />" section tells Hibernate to look for the "@Entity" in the "com.song.hibernate.entities.Student" class.

The "ApplicationStart.java" is responsible to start the Spring Boot application and initiate the "@Bean" to create the singleton "SessionFactory".

package com.song.web.boot;
    
import javax.servlet.Filter;
    
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Scope;
    
import com.song.web.filter.NocacheFilter;
    
@SpringBootApplication
@ComponentScan({ "com.song.web.controller" })
public class ApplicationStart extends SpringBootServletInitializer {
    public static void main (String[] args) {
        SpringApplication.run(ApplicationStart.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ApplicationStart.class);
    }
    
    @Bean
    public EmbeddedServletContainerCustomizer portCustomizer() {
        return (container -> { container.setPort(8090); });
    }
    
    @Bean
    public FilterRegistrationBean noCacheFilter() {
        Filter filter = new NocacheFilter();
        
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(filter);
        registration.setOrder(1);
        
        return registration;
    }
    
    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public SessionFactory sessionFactory() {
        return new Configuration().configure().buildSessionFactory();
    }
}

The "ApplicationStart" class is a standard Spring Boot start-up class.

  • The "@Bean" method "portCustomizer()" configures the application to listen to the port number "8090";
  • The "@Bean" method "noCacheFilter()" configures the application to send headers to disable all the browser caching;
  • The "@Bean" method "sessionFactory()" creates a "SessionFactory" based on the configuration in the "hibernate.cfg.xml". It is a singleton which can be "@Autowired" into the places where it is used.

In this example, the way to create a "SessionFactory" in a "@Bean" method is experimental. It is convenient, but it has problems. If the database server is not running, the application will fail to start because the creation of the  "SessionFactory" will fail. You may want to still use a standard singleton pattern to create the "SessionFactory". You can refer to this example on how to create a "SessionFactory".

We can then use the "SessionFactory" to query the database in the "ExampleController.java".

package com.song.web.controller;
    
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
    
    
import com.song.hibernate.entities.Student;
    
@Controller
public class ExampleController {
    @Autowired
    private SessionFactory sessionFactory;
    
    @ResponseBody
    @RequestMapping(value = "/getStudent", method=RequestMethod.GET)
    public Student getStudent() {
        Student student = null;
        
        try(Session session = sessionFactory.openSession()) {
            student = session.get(Student.class, 2);
        } 
        
        return student;
    }
}
  • The singleton "SessionFactory" is "@Autowired" into the "ExampleController";
  • The singleton "SessionFactory" is used to open a session in the "getStudent()" method;
  • A "Session" is an "AutoCloseable" object;
  • A Student object is obtained through the "Session". It is responded to the HTTP request though the "getStudent()" method.

Run the Application

If you load the project into Eclipse, you can directly run/debug the application in Eclipse by selecting the "ApplicationStart" class as the start-up class.

Image 6

You can also run the application through Maven by the following command.

mvn spring-boot:run

After a successful "mvn clean install", you can then start the application by the following command.

java -jar target/spring-boot-example-0.0.1-SNAPSHOT.jar

With the MySQL server started, if you start the application and issue a "GET" request "http://localhost:8090/getStudent" in the "POSTMAN", you can see the following response.

Image 7

Summary

  • To use Hibernate in an application, we need to add the Maven dependency "hibernate-entitymanager";
  • To connect to a database server, we need to add the corresponding driver dependency. In this example, it is the "mysql-connector-java";
  • We need to add a "hibernate.cfg.xml" file to configure how the Hibernate "SessionFactory" is created. The location of this file can be anywhere on the hard-drive. But the default location is the "src/main/resources" directory in a Spring Boot application;
  • It is a common practice to create a singleton "SessionFactory" that is used to open all the database sessions;
  • A "SessionFactory" is thread safe, but a "Session" is not thread safe;
  • A "Session" object is an "AutoCloseable" object. You need to make sure it is closed after it is used.

Points of Interest

  • This is a note on Spring Boot and Hibernate;
  • I hope you like my postings and I hope this note can help you one way or the other.

History

First Revision - 12/18/2017.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dr. Song Li
United States United States
I have been working in the IT industry for some time. It is still exciting and I am still learning. I am a happy and honest person, and I want to be your friend.

Comments and Discussions

 
-- There are no messages in this forum --