DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Spring Data: Data Auditing Using JaVers and MongoDB
  • CRUD Operations on Deeply Nested Comments: Scalable Spring Boot and Spring Data approach
  • Manage Hierarchical Data in MongoDB With Spring
  • Spring Data JPA - Part 1

Trending

  • Enhancing Security With ZTNA in Hybrid and Multi-Cloud Deployments
  • A Simple, Convenience Package for the Azure Cosmos DB Go SDK
  • The Role of Functional Programming in Modern Software Development
  • Teradata Performance and Skew Prevention Tips
  1. DZone
  2. Data Engineering
  3. Databases
  4. Introduction to JPA Using Spring Boot Data

Introduction to JPA Using Spring Boot Data

Object relational impedance mismatch involves databases with many-to-many relationships that comparatively have mismatched data. Read on a more in-depth introduction!

By 
Ranga Karanam user avatar
Ranga Karanam
DZone Core CORE ·
Aug. 08, 17 · Tutorial
Likes (22)
Comment
Save
Tweet
Share
238.7K Views

Join the DZone community and get the full member experience.

Join For Free

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

You will learn:

  • What is JPA?
  • What is the problem solved by JPA?
  • 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.

Tools you will need:

  • Maven 3.0+ (build tool)
  • Your favorite IDE; we will use Eclipse.
  • JDK 1.8+
  • In memory database H2

What Is Object Relational Impedance Mismatch?

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, but 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 impedance 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 Impedance Mismatch

Let's consider a simple example with 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 impedance mismatch.

Example 1

The task table below is mapped to the 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 than relationships 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 

Sometimes, 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) 
  ) 

Pre-JPA Approaches: JDBC, Spring JDBC, and MyBatis

Other approaches before JPA focused on queries and how to translate results from queries to objects. Any approach using a query typically does two things:

  1. Setting parameters to the query. We need to read values from objects and set them as parameters to the query.
  2. 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 JDBC, 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. That's one of the reasons, Hibernate is called an ORM framework.

Important Concepts in JPA

Image

JPA allows mapping application classes to tables in the 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. An important thing to understand is that 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

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

Example 1

The task table below is mapped to the 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 relationships 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

Sometimes, multiple classes are mapped to a single table and vice versa. In these situations, we define an inheritance strategy. In this example, we use a strategy called  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, the following steps have to be done:

  • Launch Spring Initializr and choose the following
    • Choose com.in28minutes.springboot as Group
    • Choose H2InMemoryDbDemo as Artifact
    • Choose following dependencies
      • Web
      • JPA
      • H2 (we use H2 as our in-memory database)
  • Click Generate Project 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

Let's 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 this documentation:

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

The 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(1 L);
  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.
  • The rest of the stuff is straightforward!

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 that 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 need to know:

  1. Spring Data Commons: Defines the common concepts for all Spring Data modules.
  2. Spring Data JPA: Provides easy integration with JPA repositories.

CrudRepository

CrudRepository is the predefined 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. The 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.
  • The rest of the stuff is straightforward.

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.

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(1 L);
  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());
 }
}

And that's it!

Spring Framework Database Relational database Data (computing) Spring Boot Spring Data

Published at DZone with permission of Ranga Karanam, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Data: Data Auditing Using JaVers and MongoDB
  • CRUD Operations on Deeply Nested Comments: Scalable Spring Boot and Spring Data approach
  • Manage Hierarchical Data in MongoDB With Spring
  • Spring Data JPA - Part 1

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!