Spring Boot and Spring Data JPA Tutorial
View more Tutorials:
On the Eclipse, create a Spring Boot project.

Select the technologies to be used in this project, including JPA and a database that you are familiar with.


Add the following configuration snippet to the pom.xml file if you want to work with the Oracle database:
** Oracle **
<dependencies> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc7</artifactId> <version>12.1.0.2</version> </dependency> </dependencies> <repositories> <!-- Repository for ORACLE ojdbc6. --> <repository> <id>codelds</id> <url>https://code.lds.org/nexus/content/groups/main-repo</url> </repository> </repositories>
The full content of pom.xml file:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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.example</groupId> <artifactId>SpringBootDataJPA</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>SpringBootDataJPA</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc7</artifactId> <version>12.1.0.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <repositories> <!-- Repository for ORACLE ojdbc6. --> <repository> <id>codelds</id> <url>https://code.lds.org/nexus/content/groups/main-repo</url> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
SpringBootDataJpaApplication.java
package org.o7planning.sbdatajpa; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootDataJpaApplication { public static void main(String[] args) { SpringApplication.run(SpringBootDataJpaApplication.class, args); } }
For the Spring Boot to be able to connect to a database, you need to configure in the applications.properties file. You can use any database with which you are familiar. Below are 4 configurations corresponding to 4 most common kinds of databases (MySQL, Oracle, SQL Server, PostGres).
In practice, let's create a empty schema named "mydatabase". The JPA will create tables corresponding to the Entities included in the application.
application.properties (MySQL)
# =============================== # DATABASE # =============================== spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase spring.datasource.username=root spring.datasource.password=12345 # =============================== # JPA / HIBERNATE # =============================== spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
application.properties (Oracle)
# =============================== # DATABASE # =============================== spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@localhost:1521:db12c spring.datasource.username=mydatabase spring.datasource.password=12345 # =============================== # JPA / HIBERNATE # =============================== spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
application.properties (SQL Server)
# =============================== # DATABASE # =============================== spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver spring.datasource.url=jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=mydatabase spring.datasource.username=sa spring.datasource.password=12345 # =============================== # JPA / HIBERNATE # =============================== spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
application.properties (PostGres)
# =============================== # DATABASE CONNECTION # =============================== spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase spring.datasource.username=postgres spring.datasource.password=12345 # =============================== # JPA / HIBERNATE # =============================== spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect # Fix Postgres JPA Error: # Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented. spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
In the JPA, each Entity class will correspond to one table in the database. There are very many tables in the database, therefore, there will be a lot of entity classes. You frequently have to work with Entities, and write DAO classes (Data Access Object) to manipulate data through these Entities. This is actually a boring job.

OK, I will tell you why it is boring. Let's imagine that you have 2 tables in the database such as EMPLOYEE & DEPARTMENT, and you have 2 corresponding Entity classes such as Employee & Department.
To manipulate with Employee, you write a DAO class including similar methods as follows:
- Employee findById(Long id)
- List<Employee> findAll()
- List<Employee> findByName(String likeName)
- .....
Certainly, to manipulate with the Department, you also do the same thing and if Entities are too many, it will take you so much time.

Spring Data JPA is a library of Spring. According to the rule of the Spring Data JPA, you just need to define an extended interface- Repository<T,ID> interface, and declare methods to manipulate with the data of this Entity. The Spring Data JPA will create a class that implements that interface for you.

Employee.java
package org.o7planning.sbdatajpa.entity; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; @Entity @Table(name = "EMPLOYEE") public class Employee { @Id private Long id; @Column(name = "Emp_No", length = 30, nullable = false) private String empNo; @Column(name = "Full_Name", length = 128, nullable = false) private String fullName; @Temporal(TemporalType.DATE) @Column(name = "Hire_Date", nullable = false) private Date hireDate; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getEmpNo() { return empNo; } public void setEmpNo(String empNo) { this.empNo = empNo; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public Date getHireDate() { return hireDate; } public void setHireDate(Date hireDate) { this.hireDate = hireDate; } @Override public String toString() { return this.getEmpNo() + ", " + this.getFullName(); } }
EmployeeRepository Interface extends CrudRepository<Employee, Long> interface.It has methods to manipulate with the Employee entity. The Spring Data JPA will automatically create a class that implements this interface at the time of running the application.
EmployeeRepository.java
package org.o7planning.sbdatajpa.repository; import java.util.Date; import java.util.List; import org.o7planning.sbdatajpa.entity.Employee; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; // This is an Interface. // No need Annotation here. public interface EmployeeRepository extends CrudRepository<Employee, Long> { // Long: Type of Employee ID. Employee findByEmpNo(String empNo); List<Employee> findByFullNameLike(String fullName); List<Employee> findByHireDateGreaterThan(Date hireDate); @Query("SELECT coalesce(max(e.id), 0) FROM Employee e") Long getMaxId(); }
The Spring Data JPA will write code for your abstract methods, therefore, you need to tell the Spring Data JPA what you want through the name of method.
Keyword | Sample | Equivalent to |
---|---|---|
GreaterThan | findByAgeGreaterThan(int age) | Select e from Person e where e.age > :age |
LessThan | findByAgeLessThan(int age) | Select e from Person e where e.age < :age |
Between | findByAgeBetween(int from, int to) | Select e from Person e where e.age between :from and :to |
IsNotNull, NotNull | findByFirstnameNotNull() | Select e from Person e where e.firstname is not null |
IsNull, Null | findByFirstnameNull() | Select e from Person e where e.firstname is null |
Like | findByFirstnameLike(String name) | Select e from Person e where e.firstname like :name |
(No keyword) | findByFirstname(String name) | Select e from Person e where e.firstname = :name |
Not | findByFirstnameNot(String name) | Select e from Person e where e.firstname <> :name |
..... |
You can also create interfaces with custom methods. In this case, you have to write the class to implement such interface.
EmployeeRepositoryCustom.java
package org.o7planning.sbdatajpa.repository; import java.util.Date; public interface EmployeeRepositoryCustom { public Long getMaxEmpId(); public long updateEmployee(Long empId, String fullName, Date hireDate); }
EmployeeRepositoryCustomImpl.java
package org.o7planning.sbdatajpa.repository; import java.util.Date; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.Query; import org.o7planning.sbdatajpa.entity.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @Repository public class EmployeeRepositoryCustomImpl implements EmployeeRepositoryCustom { @Autowired EntityManager entityManager; @Override public Long getMaxEmpId() { try { String sql = "SELECT coalesce(max(e.id), 0) FROM Employee e"; Query query = entityManager.createQuery(sql); return (Long) query.getSingleResult(); } catch (NoResultException e) { return 0L; } } @Override public long updateEmployee(Long empId, String fullName, Date hireDate) { Employee e = entityManager.find(Employee.class, empId); if (e == null) { return 0; } e.setFullName(fullName); e.setHireDate(hireDate); entityManager.flush(); return 1; } }
MainController.java
package org.o7planning.sbdatajpa.controller; import java.util.Date; import java.util.List; import java.util.Random; import org.o7planning.sbdatajpa.entity.Employee; import org.o7planning.sbdatajpa.repository.EmployeeRepository; 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.ResponseBody; @Controller public class MainController { @Autowired private EmployeeRepository employeeRepository; private static final String[] NAMES = new String[] { "Tom", "Jerry", "Donald" }; @ResponseBody @RequestMapping("/") public String home() { String html = ""; html += "<ul>"; html += " <li><a href='/testInsert'>Test Insert</a></li>"; html += " <li><a href='/showAllEmployee'>Show All Employee</a></li>"; html += " <li><a href='/showFullNameLikeTom'>Show All 'Tom'</a></li>"; html += " <li><a href='/deleteAllEmployee'>Delete All Employee</a></li>"; html += "</ul>"; return html; } @ResponseBody @RequestMapping("/testInsert") public String testInsert() { Long empIdMax = this.employeeRepository.getMaxId(); Employee employee = new Employee(); int random = new Random().nextInt(3); long id = empIdMax + 1; String fullName = NAMES[random] + " " + id; employee.setId(id); employee.setEmpNo("E" + id); employee.setFullName(fullName); employee.setHireDate(new Date()); this.employeeRepository.save(employee); return "Inserted: " + employee; } @ResponseBody @RequestMapping("/showAllEmployee") public String showAllEmployee() { Iterable<Employee> employees = this.employeeRepository.findAll(); String html = ""; for (Employee emp : employees) { html += emp + "<br>"; } return html; } @ResponseBody @RequestMapping("/showFullNameLikeTom") public String showFullNameLikeTom() { List<Employee> employees = this.employeeRepository.findByFullNameLike("Tom"); String html = ""; for (Employee emp : employees) { html += emp + "<br>"; } return html; } @ResponseBody @RequestMapping("/deleteAllEmployee") public String deleteAllEmployee() { this.employeeRepository.deleteAll(); return "Deleted!"; } }
