Introduction to JPA and Hibernate using Spring Boot Data Jpa


This guide will help you understand what JPA is and setup a simple JPA example using Spring Boot.

You will learn

  • What is JPA?
  • What is the problem solved by JPA - Object Relational Impedence?
  • What are the alternatives to JPA?
  • What is Hibernate and How does it relate to JPA?
  • What is Spring Data JPA?
  • How to create a simple JPA project using Spring Boot Data JPA Starter?

References

1 hour video courses on all popular frameworks!

Tools you will need

  • Maven 3.0+ is your build tool
  • Your favorite IDE. We use Eclipse.
  • JDK 1.8+
  • In memory database H2

What is Object Relational Impedence Mismatch?

Image

Java is an object oriented programming language. In Java, all data is stored in objects.

Typically, Relational databases are used to store data (These days, a number of other NoSQL data stores are also becoming popular - We will stay away from them, for now). Relational databases store data in tables.

The way we design objects is different from the way the relational databases are designed. This results in an impedence mismatch.

  • Object Oriented programming consists of concepts like encapsulation, inheritance, interfaces and polymorphism
  • Relational databases are made up of Tables with concepts like normalization

Examples of Object Relational Impedence Mismatch

Lets consider a simple example - Employees and Tasks.

Each Employee can have multiple Tasks. Each Task can be shared by multiple Employees. There is a Many to Many relationship between them. Let’s consider a few examples of impedence mismatch.

Example 1 : Task table below is mapped to Task Table. However, there are mismatches in column names.

public class Task {
	private int id;

	private String desc;

	private Date targetDate;

	private boolean isDone;

	private List<Employee> employees;
}
 CREATE TABLE task 
  ( 
     id          INTEGER GENERATED BY DEFAULT AS IDENTITY, 
     description VARCHAR(255), 
     is_done     BOOLEAN, 
     target_date TIMESTAMP, 
     PRIMARY KEY (id) 
  ) 

Example 2 : Relationships between objects are expressed in a different way compared with relationship between tables.

Each Employee can have multiple Tasks. Each Task can be shared by multiple Employees. There is a Many to Many relationship between them.

public class Employee {
   
     //Some other code
	
	private List<Task> tasks;
}

public class Task {

     //Some other code

	private List<Employee> employees;
}
CREATE TABLE employee 
  ( 
     id            BIGINT NOT NULL, 
     OTHER_COLUMNS
  ) 


  CREATE TABLE employee_tasks 
  ( 
     employees_id BIGINT NOT NULL, 
     tasks_id     INTEGER NOT NULL 
  ) 

  CREATE TABLE task 
  ( 
     id          INTEGER GENERATED BY DEFAULT AS IDENTITY, 
     OTHER_COLUMNS
  ) 

Example 3 : Some times multiple classes are mapped to a single table and vice-versa

Objects

public  class Employee {	
    //Other Employee Attributes
}

public class FullTimeEmployee extends Employee {
	protected Integer salary;
}

public class PartTimeEmployee extends Employee {
	protected Float hourlyWage;
}

Tables

CREATE TABLE employee 
  ( 
     employee_type VARCHAR(31) NOT NULL, 
     id            BIGINT NOT NULL, 
     city          VARCHAR(255), 
     state         VARCHAR(255), 
     street        VARCHAR(255), 
     zip           VARCHAR(255), 

     hourly_wage   FLOAT,  --PartTimeEmployee

     salary        INTEGER, --FullTimeEmployee

     PRIMARY KEY (id) 
  ) 

Other approaches before JPA - JDBC, Spring JDBC & myBatis

Other approaches before JPA focused on queries and how to translate results from queries to objects.

Any approach using query typically does two things

  • Setting parameters to the query. We need to read values from objects and set them as parameters to the query.
  • Liquidation of results from the query. The results from the query need to be mapped to the beans.

JDBC

  • JDBC stands for Java Database Connectivity
  • It used concepts like Statement, PreparedStatement and ResultSet
  • In the example below, the query used is Update todo set user=?, desc=?, target_date=?, is_done=? where id=?
  • The values needed to execute the query are set into the query using different set methods on the PreparedStatement
  • Results from the query are populated into the ResultSet. We had to write code to liquidate the ResultSet into objects.

Update Todo

Connection connection = datasource.getConnection();

PreparedStatement st = connection.prepareStatement(
		"Update todo set user=?, desc=?, target_date=?, is_done=? where id=?");

st.setString(1, todo.getUser());
st.setString(2, todo.getDesc());
st.setTimestamp(3, new Timestamp(
		todo.getTargetDate().getTime()));
st.setBoolean(4, todo.isDone());
st.setInt(5, todo.getId());

st.execute();

st.close();

connection.close();

Retrieve a Todo

Connection connection = datasource.getConnection();

PreparedStatement st = connection.prepareStatement(
		"SELECT * FROM TODO where id=?");

st.setInt(1, id);

ResultSet resultSet = st.executeQuery();


if (resultSet.next()) {

    Todo todo = new Todo();
	todo.setId(resultSet.getInt("id"));
	todo.setUser(resultSet.getString("user"));
	todo.setDesc(resultSet.getString("desc"));
	todo.setTargetDate(resultSet.getTimestamp("target_date"));
	return todo;
}

st.close();

connection.close();

return null;

Spring JDBC

  • Spring JDBC provides a layer on top of JDBC
  • It used concepts like JDBCTemplate
  • Typically needs lesser number of lines compared to JDBC as following are simplified
    • mapping parameters to queries
    • liquidating resultsets to beans

Update Todo

jdbcTemplate
.update("Update todo set user=?, desc=?, target_date=?, is_done=? where id=?",
	todo.getUser(), 
	todo.getDesc(),
	new Timestamp(todo.getTargetDate().getTime()),
	todo.isDone(), 
	todo.getId());

Retrieve a Todo

@Override
public Todo retrieveTodo(int id) {

	return jdbcTemplate.queryForObject(
			"SELECT * FROM TODO where id=?",
			new Object[] { id }, new TodoMapper());

}

Reusable Row Mapper

// new BeanPropertyRowMapper(TodoMapper.class)
class TodoMapper implements RowMapper<Todo> {
	@Override
	public Todo mapRow(ResultSet rs, int rowNum)
			throws SQLException {
		Todo todo = new Todo();

		todo.setId(rs.getInt("id"));
		todo.setUser(rs.getString("user"));
		todo.setDesc(rs.getString("desc"));
		todo.setTargetDate(
				rs.getTimestamp("target_date"));
		todo.setDone(rs.getBoolean("is_done"));
		return todo;
	}
}	

myBatis

MyBatis removes the need for manually writing code to set parameters and retrieve results. It provides simple XML or Annotation based configuration to map Java POJOs to database.

We compare the approaches used to write queries below:

  • JDBC or Spring JDBC - Update todo set user=?, desc=?, target_date=?, is_done=? where id=?
  • myBatis - Update todo set user=#{user}, desc=#{desc}, target_date=#{targetDate}, is_done=#{isDone} where id=#{id}

Update Todo and Retrieve Todo

@Mapper
public interface TodoMybatisService
		extends TodoDataService {

	@Override
	@Update("Update todo set user=#{user}, desc=#{desc}, target_date=#{targetDate}, is_done=#{isDone} where id=#{id}")
	public void updateTodo(Todo todo) throws SQLException;

	@Override
	@Select("SELECT * FROM TODO WHERE id = #{id}")
	public Todo retrieveTodo(int id) throws SQLException;
}

public class Todo {

	private int id;

	private String user;

	private String desc;

	private Date targetDate;

	private boolean isDone;
}

Common features of DBC, Spring JDBC and myBatis

  • JDBC, Spring JDBC and myBatis involve writing queries.
  • In big application, queries can become complex. Especially when we retrieve data from multiple tables.
  • This creates a problem whenever there are changes in the structure of the database.

How does JPA Work?

JPA evolved as a result of a different thought process. How about mapping the objects directly to tables?

  • Entities
  • Attributes
  • Relationships

This Mapping is also called ORM - Object Relational Mapping. Before JPA, ORM was the term more commonly used to refer to these frameworks. Thats one of the reasons, Hibernate is called a ORM framework.

Important Concepts in JPA

Image

JPA allows to map application classes to tables in database.

  • Entity Manager - Once the mappings are defined, entity manager can manage your entities. Entity Manager handles all interactions with the database
  • JPQL (Java Persistence Query Language) - Provides ways to write queries to execute searches against entities. Important thing to understand is the these are different from SQL queries. JPQL queries already understand the mappings that are defined between entities. We can add additional conditions as needed.
  • Criteria API defines a Java based API to execute searches against databases.

JPA vs Hibernate

Hibernate is one of the most popular ORM frameworks.

JPA defines the specification. It is an API.

  • How do you define entities?
  • How do you map attributes?
  • How do you map relationships between entities?
  • Who manages the entities?

Hibernate is one of the popular implementations of JPA.

  • Hibernate understands the mappings that we add between objects and tables. It ensures that data is stored/retrieved from the database based on the mappings.
  • Hibernate also provides additional features on top of JPA. But depending on them would mean a lock in to Hibernate. You cannot move to other JPA implementations like Toplink.

Examples of JPA Mappings

Lets look at a few examples to understand how JPA can be used to map objects to tables.

Example 1

Task table below is mapped to Task Table. However, there are mismatches in column names. We use a few JPA annotations to do the mapping

  • @Table(name = “Task”)
  • @Id
  • @GeneratedValue
  • @Column(name = “description”)
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "Task")
public class Task {
	@Id
	@GeneratedValue
	private int id;

	@Column(name = "description")
	private String desc;

	@Column(name = "target_date")
	private Date targetDate;

	@Column(name = "is_done")
	private boolean isDone;

}
 CREATE TABLE task 
  ( 
     id          INTEGER GENERATED BY DEFAULT AS IDENTITY, 
     description VARCHAR(255), 
     is_done     BOOLEAN, 
     target_date TIMESTAMP, 
     PRIMARY KEY (id) 
  ) 

Example 2

Relationships between objects are expressed in a different way compared to relationship between tables.

Each Employee can have multiple Tasks. Each Task can be shared by multiple Employees. There is a Many to Many relationship between them. We use @ManyToMany annotation to establish the relationship.

public class Employee {
   
     //Some other code
	
	@ManyToMany
	private List<Task> tasks;
}

public class Task {

     //Some other code

	@ManyToMany(mappedBy = "tasks")
	private List<Employee> employees;
}
CREATE TABLE employee 
  ( 
     id            BIGINT NOT NULL, 
     OTHER_COLUMNS
  ) 


  CREATE TABLE employee_tasks 
  ( 
     employees_id BIGINT NOT NULL, 
     tasks_id     INTEGER NOT NULL 
  ) 

  CREATE TABLE task 
  ( 
     id          INTEGER GENERATED BY DEFAULT AS IDENTITY, 
     OTHER_COLUMNS
  ) 

Example 3

Some times multiple classes are mapped to a single table and vice-versa. In these situations, we define a inheritance strategy. In this example, we use a strategy of InheritanceType.SINGLE_TABLE.

Objects

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "EMPLOYEE_TYPE")
public  class Employee {	
    //Other Employee Attributes
}

public class FullTimeEmployee extends Employee {
	protected Integer salary;
}

public class PartTimeEmployee extends Employee {
	protected Float hourlyWage;
}

Tables

CREATE TABLE employee 
  ( 
     employee_type VARCHAR(31) NOT NULL, 
     id            BIGINT NOT NULL, 
     city          VARCHAR(255), 
     state         VARCHAR(255), 
     street        VARCHAR(255), 
     zip           VARCHAR(255), 

     hourly_wage   FLOAT,  --PartTimeEmployee

     salary        INTEGER, --FullTimeEmployee

     PRIMARY KEY (id) 
  ) 

Step by Step Code Example

Bootstrapping a Web application with Spring Initializr

Creating a JPA application with Spring Initializr is very simple.

Image

As shown in the image above, following steps have to be done

  • Launch Spring Initializr http://start.spring.io/ and choose the following
    • Choose com.in28minutes.springboot as Group
    • Choose H2InMemoryDbDemo as Artifact
    • Choose following dependencies
      • Web
      • JPA
      • H2 - We use H2 as in memory database
  • Click Generate Project button at the bottom of the page.
  • Import the project into Eclipse.

Structure of the project created

  • H2InMemoryDbDemoApplication.java - Spring Boot Launcher. Initializes Spring Boot Auto Configuration and Spring Application Context.
  • application.properties - Application Configuration file.
  • H2InMemoryDbDemoApplicationTests.java - Simple launcher for use in unit tests.
  • pom.xml - Included dependencies for Spring Boot Starter Web and Data JPA. Uses Spring Boot Starter Parent as parent pom.

Important dependencies are shown below:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>

User Entity

Lets define a bean User and add the appropriate JPA annotations.

package com.example.h2.user;

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

@Entity
@NamedQuery(query = "select u from User u", name = "query_find_all_users")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	private String name;// Not perfect!! Should be a proper object!

	private String role;// Not perfect!! An enum should be a better choice!

	protected User() {
	}

	public User(String name, String role) {
		super();
		this.name = name;
		this.role = role;
	}

}

Important things to note:

  • @Entity: Specifies that the class is an entity. This annotation is applied to the entity class.
  • @NamedQuery: Specifies a static, named query in the Java Persistence query language.
  • @Id: Specifies the primary key of an entity.
  • @GeneratedValue: Provides for the specification of generation strategies for the values of primary keys.
  • protected User(): Default constructor to make JPA Happy

User Service to talk to Entity Manager

Typically with JPA we need to create a service to talk to the entity manager. In this example, we create a UserService to manage the persistence of user entity.

@Repository
@Transactional
public class UserService {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	public long insert(User user) {
		entityManager.persist(user);
		return user.getId();
	}

	public User find(long id) {
		return entityManager.find(User.class, id);
	}
	
	public List<User> findAll() {
		Query query = entityManager.createNamedQuery(
				"query_find_all_users", User.class);
		return query.getResultList();
	}
}

Important things to note

  • @Repository: Spring Annotation to indicate that this component handles storing data to a data store.
  • @Transactional: Spring annotation used to simplify transaction management
  • @PersistenceContext: A persistence context handles a set of entities which hold data to be persisted in some persistence store (e.g. a database). In particular, the context is aware of the different states an entity can have (e.g. managed, detached) in relation to both the context and the underlying persistence store.
  • EntityManager : Interface used to interact with the persistence context.
  • entityManager.persist(user): Make user entity instance managed and persistent i.e. saved to database.
  • entityManager.createNamedQuery: Creates an instance of TypedQuery for executing a Java Persistence query language named query. The second parameter indicates the type of result.

Notes from http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#createNamedQuery(java.lang.String)

An EntityManager instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed. The EntityManager API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities.

The set of entities that can be managed by a given EntityManager instance is defined by a persistence unit. A persistence unit defines the set of all classes that are related or grouped by the application, and which must be colocated in their mapping to a single database.

User Entity Manager Command Line Runner

CommandLineRunner interface is used to indicate that this bean has to be run as soon as the Spring application context is initialized.

We are executing a few simple methods on the UserService.

@Component
public class UserEntityManagerCommandLineRunner implements CommandLineRunner {

	private static final Logger log = LoggerFactory.getLogger(UserEntityManagerCommandLineRunner.class);
	
	@Autowired
	private UserService userService;

	@Override
	public void run(String... args) {

		log.info("-------------------------------");
		log.info("Adding Tom as Admin");
		log.info("-------------------------------");
		User tom = new User("Tom", "Admin");
		userService.insert(tom);
		log.info("Inserted Tom" + tom);

		log.info("-------------------------------");
		log.info("Finding user with id 1");
		log.info("-------------------------------");
		User user = userService.find(1L);
		log.info(user.toString());

		log.info("-------------------------------");
		log.info("Finding all users");
		log.info("-------------------------------");
		log.info(userService.findAll().toString());
	}
}

Important things to note:

  • @Autowired private UserService userService: Autowire the user service.
  • Rest of the stuff is straight forward.

Spring Data JPA

Spring Data aims to provide a consistent model for accessing data from different kinds of data stores.

UserService (which we created earlier) contains a lot of redundant code which can be easily generalized. Spring Data aims to simplify the code below.

@Repository
@Transactional
public class UserService {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	public long insert(User user) {
		entityManager.persist(user);
		return user.getId();
	}

	public User find(long id) {
		return entityManager.find(User.class, id);
	}
	
	public List<User> findAll() {
		Query query = entityManager.createNamedQuery(
				"query_find_all_users", User.class);
		return query.getResultList();
	}
}

As far as JPA is concerned there are two Spring Data modules that you would need to know

  • Spring Data Commons - Defines the common concepts for all Spring Data Modules.
  • Spring Data JPA - Provides easy integration with JPA repositories.

CrudRepository

CrudRepository is the pre-defined core repository class (in Spring Data Commons) enabling the basic CRUD functions on a repository. Important methods are shown below.

public interface CrudRepository<T, ID extends Serializable>
    extends Repository<T, ID> {

    <S extends T> S save(S entity);

    T findOne(ID primaryKey);       

    Iterable<T> findAll();          

    Long count();                   

    void delete(T entity);          

    boolean exists(ID primaryKey);  

    // … more functionality omitted.
}

JpaRepository

JpaRepository (Defined in Spring Data JPA) is the JPA specific Repository interface.

public interface JpaRepository<T, ID extends Serializable>
		extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

We will now use the JpaRepository to manage the User entity. Below snippet shows the important details. We would want the UserRepository to manage the User entity which has a primary key of type Long.

package com.example.h2.user;

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

public interface UserRepository extends JpaRepository<User, Long> {
}

User Repository CommandLineRunner

The code below is very simple. CommandLineRunner interface is used to indicate that this bean has to be run as soon as the Spring application context is initialized. We are executing a few simple methods on the UserRepository.

package com.example.h2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import com.example.h2.user.User;
import com.example.h2.user.UserRepository;

@Component
public class UserRepositoryCommandLineRunner implements CommandLineRunner {

	private static final Logger log = LoggerFactory.getLogger(UserRepositoryCommandLineRunner.class);

	@Autowired
	private UserRepository userRepository;

	@Override
	public void run(String... args) {
		User harry = new User("Harry", "Admin");
		userRepository.save(harry);
		log.info("-------------------------------");
		log.info("Finding all users");
		log.info("-------------------------------");
		for (User user : userRepository.findAll()) {
			log.info(user.toString());
		}
	}

}

Important things to note:

  • @Autowired private UserRepository userRepository: Auto wiring the user repository.
  • Rest of the stuff is straight forward.

H2 Console

We will enable h2 console in /src/main/resources/application.properties

spring.h2.console.enabled=true

You can start the application by running H2InMemoryDbDemoApplication as a java application.

You can also run the H2-Console on the browser

  • http://localhost:8080/h2-console
  • Use db url jdbc:h2:mem:testdb

Questions

  • Where is the database created?
    • In Memory - Using H2
  • What schema is used to create the tables?
    • Created based on the entities defined
  • Where are the tables created?
    • Created based on the entities defined
    • In Memory - Using H2
  • Can I see the data in the database?
    • http://localhost:8080/h2-console
    • Use db url jdbc:h2:mem:testdb
  • Where is Hibernate coming in from?
    • Through Spring Data JPA Starter
  • How is a datasource created?
    • Through Spring Boot Auto Configuration

Magic of Spring Boot and in Memory Database

  • Zero project setup or infrastructure
  • Zero Configuration
  • Zero Maintainance
  • Easy to use for Learning and Unit Tests
  • Simple Configuration to switch to a real database

Restrictions of using inmemory database

  • Data is not persisted between restarts

Complete Code Example

/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>jpa-in-10-steps</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>jpa-with-in-memory-db-in-10-steps</name>
	<description>Demo project for in memory database H2</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.BUILD-SNAPSHOT</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-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</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>

	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>


</project>

/src/main/java/com/example/h2/H2InMemoryDbDemoApplication.java

package com.example.h2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class H2InMemoryDbDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(H2InMemoryDbDemoApplication.class, args);
	}
}

/src/main/java/com/example/h2/user/User.java

package com.example.h2.user;

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

@Entity
@NamedQuery(query = "select u from User u", name = "query_find_all_users")
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	private String name;// Not perfect!! Should be a proper object!
	private String role;// Not perfect!! An enum should be a better choice!

	protected User() {
	}

	public User(String name, String role) {
		super();
		this.name = name;
		this.role = role;
	}

	public Long getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public String getRole() {
		return role;
	}

	@Override
	public String toString() {
		return String.format("User [id=%s, name=%s, role=%s]", id, name, role);
	}

}

/src/main/java/com/example/h2/user/UserRepository.java

package com.example.h2.user;

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

public interface UserRepository extends JpaRepository<User, Long> {
}

/src/main/java/com/example/h2/user/UserService.java

package com.example.h2.user;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;

import org.springframework.stereotype.Repository;

@Repository
@Transactional
public class UserService {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	public long insert(User user) {
		entityManager.persist(user);
		return user.getId();
	}

	public User find(long id) {
		return entityManager.find(User.class, id);
	}
	
	public List<User> findAll() {
		Query query = entityManager.createNamedQuery(
				"query_find_all_users", User.class);
		return query.getResultList();
	}
}

/src/main/java/com/example/h2/UserEntityManagerCommandLineRunner.java

package com.example.h2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import com.example.h2.user.User;
import com.example.h2.user.UserService;

@Component
public class UserEntityManagerCommandLineRunner implements CommandLineRunner {

	private static final Logger log = LoggerFactory.getLogger(UserEntityManagerCommandLineRunner.class);
	
	@Autowired
	private UserService userService;

	@Override
	public void run(String... args) {

		log.info("-------------------------------");
		log.info("Adding Tom as Admin");
		log.info("-------------------------------");
		User tom = new User("Tom", "Admin");
		userService.insert(tom);
		log.info("Inserted Tom" + tom);

		log.info("-------------------------------");
		log.info("Finding user with id 1");
		log.info("-------------------------------");
		User user = userService.find(1L);
		log.info(user.toString());

		log.info("-------------------------------");
		log.info("Finding all users");
		log.info("-------------------------------");
		log.info(userService.findAll().toString());
	}
}

/src/main/java/com/example/h2/UserRepositoryCommandLineRunner.java

package com.example.h2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import com.example.h2.user.User;
import com.example.h2.user.UserRepository;

@Component
public class UserRepositoryCommandLineRunner implements CommandLineRunner {

	private static final Logger log = LoggerFactory.getLogger(UserRepositoryCommandLineRunner.class);

	@Autowired
	private UserRepository userRepository;

	@Override
	public void run(String... args) {
		User harry = new User("Harry", "Admin");
		userRepository.save(harry);
		log.info("-------------------------------");
		log.info("Finding all users");
		log.info("-------------------------------");
		for (User user : userRepository.findAll()) {
			log.info(user.toString());
		}
	}

}

/src/main/resources/application.properties

spring.h2.console.enabled=true
#logging.level.org.hibernate=debug
spring.jpa.show-sql=true

/src/main/resources/data.sql

insert into user (id, name, role) values (101, 'Ranga', 'Admin');
insert into user (id, name, role) values (102, 'Ravi', 'User');
insert into user (id, name, role) values (103, 'Satish', 'Admin');

/src/test/java/com/example/h2/H2InMemoryDbDemoApplicationTests.java

package com.example.h2;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class H2InMemoryDbDemoApplicationTests {

	@Test
	public void contextLoads() {
	}

}

/src/test/java/com/example/h2/user/UserRepositoryTest.java

package com.example.h2.user;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.h2.user.UserRepository;

@DataJpaTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {

	@Autowired
	UserRepository userRepository;

	@Autowired
	TestEntityManager entityManager;

	@Test
	public void check_todo_count() {
		assertEquals(3, userRepository.count());
	}
}

Subscribe to get amazing offers on all our courses.

Find out how in28Minutes reached 100,000 Learners on Udemy in 2 years. The in28minutes Way - Our approach to creating awesome learning experiences.

Related Posts

Spring Boot Tutorials for Beginners

At in28Minutes, we are creating a number of videos, articles & courses on Spring Boot for Beginners and experienced developers.

Introduction to Web Services - Restful and SOAP

Introduction to Web Services - Restful and SOAP

Spring Boot vs Spring MVC vs Spring - How do they compare?

How does Spring Boot compare with Spring MVC and Spring?

Creating a Web Application with Spring Boot

Setting up a basic web application with Spring Boot is a cake walk. We will create a simple web application using Spring Initializr and add JSP features to it.

Secure Rest Services and Web Applications with Spring Boot Security Starter

Spring Boot Starter Security is the recommended starter for enabling security on web application - including REST services.

Creating a REST Service with Spring Boot

Setting up a basic example REST Service with Spring Boot. Its a cake walk.

Introduction to Spring Boot Starter Parent

Key goal of Spring Boot is to enable a quick start to developing production ready applications. Spring Boot Starter Parent plays a key role in managing dependency versions and having the right plug-ins configured.

Spring Boot Starter Projects

Key goal of Spring Boot is to enable a quick start to developing production ready applications. Most important components behind the features of Spring Boot are the Spring Boot Starter Projects.

Writing Integration Tests for Rest Services with Spring Boot

Setting up a basic REST Service with Spring Boot is a cake walk. We will go one step further and add great integration tests!

What is Spring Boot Auto Configuration?

Auto Configuration is the most important feature in Spring Boot. We will learn important concepts about Auto Configuration with a couple of examples.