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.
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.
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.
You can issue the following SQL script through the MySQL Workbench to create the database table and add some data.
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.
The Example - Spring Boot + Hibernate
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.
='1.0'='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>
<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.
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.
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