Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

A Note on Spring Boot - 3

5.00/5 (1 vote)
18 Dec 2017CPOL6 min read 9.5K   46  
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.

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.

Java
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
<?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.

Java
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.

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 posts and I hope this note can help you one way or the other.

History

  • 18th December, 2017: First revision

License

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