Learnitweb

Spring Boot with Hibernate

In this tutorial, we’ll discuss how to integrate Spring Boot and Hibernate. In this tutorial, we’ll create a REST application and will integrate Hibernate.

Step 1: Create a Spring Boot application with Hibernate dependencies

In this tutorial we are using MySql as database. We’ll create a Spring Boot application with following dependencies:

  • spring-boot-starter-data-jpa
  • spring-boot-starter-web
  • mysql-connector-java

You can use Spring Initializr to create your application. Using Spring Initializr is very simple and easy to use. Once you have created your application using Spring Initializr, you can import your application in your IDE. We are using STS for this tutorial.

In maven project the pom.xml looks like this.

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.learnitweb</groupId>
	<artifactId>springHibernateDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springHibernateDemo</name>
	<description>Demo of Spring Boot with Hibernate</description>
	<properties>
		<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>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

If spring-boot-starter-data-jpa dependency is used, Spring will try to configure the datasource. Java’s javax.sql.DataSource interface provides a standard method of working with database connections. Typically, a datasource uses a URL along with credentials to establish a database connection. After creating the application, if you try to start the application, you may get the following error:

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
	If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
	If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

At least the spring.datasource.url property should be set otherwise, Spring Boot tries to auto-configure an embedded database.

Step 2. Configuration

Next step is to defined the properties in application.properties to configure the database connection details. We are using the following properties in application.properties.

spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

# 'create' will generate DDL 
spring.jpa.hibernate.ddl-auto=create

# property to show sql in console
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

Step 3: Create Entity

We are creating a Customer entity. We are using @Table annotation to specify the table name with which this entity will be mapped in database. This annotation is not mandatory. If not used table name will be same as that of entity.

Customer.java

package com.learnitweb.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Customer")
public class Customer {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String firstName;
	private String lastName;

	public Customer() {
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

}

Step 4: Write controller, service and repository

CustomerController.java

package com.learnitweb.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.learnitweb.dto.CustomerData;
import com.learnitweb.service.CustomerService;

@RestController
@RequestMapping("/customers")
public class CustomerController {

	@Autowired
	CustomerService customerService;

	/*
	 * Controller to get all customers
	 */
	@GetMapping
	public List<CustomerData> getCustomers() {
		return customerService.getAllCustomers();
	}

	/*
	 * Controller to get detail of particular customer
	 */
	@GetMapping("/customer/{id}")
	public CustomerData getCustomer(@PathVariable Long id) {
		return customerService.getCustomerById(id);
	}

	/*
	 * Controller to save customer
	 */
	@PostMapping("/customer")
	public CustomerData saveCustomer(final @RequestBody CustomerData customerData) {
		return customerService.saveCustomer(customerData);
	}
}

CustomerRepository.java

package com.learnitweb.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.learnitweb.entity.Customer;

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {

}

CustomerService.java

package com.learnitweb.service;

import java.util.List;

import com.learnitweb.dto.CustomerData;

public interface CustomerService {
	public CustomerData saveCustomer(CustomerData customer);

	public List<CustomerData> getAllCustomers();

	public CustomerData getCustomerById(Long customerId);

}

CustomerServiceImpl.java

package com.learnitweb.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.persistence.EntityNotFoundException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.learnitweb.dto.CustomerData;
import com.learnitweb.entity.Customer;
import com.learnitweb.repository.CustomerRepository;
import com.learnitweb.service.CustomerService;

@Service
public class CustomerServiceImpl implements CustomerService {

	@Autowired
	CustomerRepository customerRepository;

	@Override
	public CustomerData saveCustomer(CustomerData customer) {
		Customer customerEntity = populateCustomerEntity(customer);
		return populateCustomerData(customerRepository.save(customerEntity));
	}

	@Override
	public List<CustomerData> getAllCustomers() {
		List<CustomerData> customers = new ArrayList<>();
		List<Customer> customerList = customerRepository.findAll();
		customerList.forEach(customer -> {
			customers.add(populateCustomerData(customer));
		});
		return customers;
	}

	@Override
	public CustomerData getCustomerById(Long customerId) {
		Optional<Customer> customerEntity = customerRepository.findById(customerId);
		if (customerEntity.isPresent()) {
			return populateCustomerData(customerEntity.get());
		} else {
			throw new EntityNotFoundException("Customer not found");
		}
	}

	private CustomerData populateCustomerData(final Customer customer) {
		CustomerData customerData = new CustomerData();
		customerData.setId(customer.getId());
		customerData.setFirstName(customer.getFirstName());
		customerData.setLastName(customer.getLastName());
		return customerData;
	}

	private Customer populateCustomerEntity(CustomerData customerData) {
		Customer customer = new Customer();
		customer.setFirstName(customerData.getFirstName());
		customer.setLastName(customerData.getLastName());
		return customer;
	}

}

CustomerData.java

package com.learnitweb.dto;

public class CustomerData {
	private Long id;
	private String firstName;
	private String lastName;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
}

Step 5: Test your application

5.1 Saving customer (POST)

spring with hibernate post

5.2 Get customer by Id

spring with hibernate get by Id

5.3 Get all customers

spring with hibernate get all customers

Reading database username and password from environment in Spring Boot

You may not want to hard code database username and password in application.properties. One reason to not do so is that if you save database username and password in property file then these will be committed as a part of your code in your version control system.

One solution is to use database username and password as environment property. In our case, we have created two environment variables DB_USER and DB_PASSWORD to save database username and password. You then have to change application.properties file like the following to read database username and password from environment:

spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASSWORD}

Note: If you are trying this in your local, you need to restart your IDE after creating environment variables.