
This guide introduces JPA and walks you through setting up a simple example in Spring Boot.

You Will Learn
- What is JPA?
- The problem JPA solves – Object-Relational Impedance Mismatch
- 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 the Spring Boot Data JPA Starter
You Will Need the Following Tools
- Maven 3.0+ – Build and dependency management tool
- An IDE of your choice – for example, Eclipse or IntelliJ IDEA
- JDK 17+ – Java Development Kit
- H2 Database – In-memory database for quick setup and testing
What is Object Relational Impedance Mismatch?

Java is an object-oriented programming language, where all data is represented and managed through objects.
In most applications, data is stored in relational databases (although NoSQL databases are also gaining popularity, we will not focus on them here). Relational databases store data in tables.
However, the way we design objects in Java is very different from how relational databases are structured, leading to what is known as an impedance mismatch.
- Object-oriented programming uses concepts like encapsulation, inheritance, interfaces, and polymorphism.
- Relational databases organize data into tables and follow principles such as normalization.
Examples of Object-Relational Impedance Mismatch
Let’s take a simple example involving Employees and Tasks.
- Each
Employeecan be assigned multiple tasks. - Each
Taskcan be shared by multiple employees.
This creates a many-to-many relationship between Employee and Task.
Now, let’s look at some examples of impedance mismatch.
Example 1: Column Naming Differences
Suppose the Task class in Java has fields like taskId and taskDescription.
In the database, the corresponding table might use column names such as id and description.
Even though they represent the same data, the mismatch in naming conventions between objects and database tables creates friction in mapping.
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: Differences in Representing Relationships
In Java, relationships between objects are expressed differently than relationships between tables in a database.
For example:
- Each
Employeeobject can have multipleTaskobjects. - Each
Taskobject can be associated with multipleEmployeeobjects.
This creates a many-to-many relationship.
In a relational database, representing this relationship typically requires a join table, which adds an extra layer
of complexity when mapping objects to tables.
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)
)
Other Approaches Before JPA — JDBC, Spring JDBC & MyBatis
Before JPA, most approaches focused on writing queries and mapping query results to objects.
Typically, any query-based approach involves two main tasks:
- Setting query parameters – reading values from objects and assigning them as parameters to the query.
- Mapping query results – converting the results returned by the query into Java objects (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 required to execute the query are set using various
setmethods on the PreparedStatement. - The results returned by the query are stored in a ResultSet, and we must manually map these results into Java 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();
Retrieved by 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 higher-level abstraction over standard JDBC.
- It introduces concepts like JdbcTemplate.
- Typically, requires fewer lines of code compared to plain JDBC, because it simplifies:
- Mapping parameters to queries
- Converting (mapping) result sets into Java objects (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 eliminates the need to manually write code for setting query parameters and mapping results.
It provides a simple XML- or annotation-based configuration to map Java POJOs to database tables.
Below, we compare the approaches used to write queries in different frameworks.
- 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}
Todo Update and Todo Retrieve
@Mapper
public interface TodoMybatisService
extends TodoDataService {
@Override
@Update("Update todo set user=#{user}, desc=#{desc}, target_date=#{targetDate}, is_done=#{isDone} where id=#{id}")
void updateTodo(Todo todo) throws SQLException;
@Override
@Select("SELECT * FROM TODO WHERE id = #{id}")
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
- All three approaches—JDBC, Spring JDBC, and MyBatis—require writing SQL queries.
- In large applications, queries can become complex, especially when retrieving data from multiple tables.
- This complexity creates problems whenever the database structure changes, requiring updates to all affected queries.
How Does JPA Work?
JPA was designed with a different approach: instead of focusing on queries, it maps Java objects directly to database tables.
Key concepts include:
- Entities – Java classes that represent database tables
- Attributes – Fields in the class that correspond to table columns
- Relationships – Associations between entities, such as one-to-many or many-to-many
This process is known as Object-Relational Mapping (ORM).
Before JPA, the term ORM was commonly used to describe frameworks like Hibernate, which is why Hibernate is often referred to as an ORM framework.
Important Concepts in JPA

JPA allows you to map application classes directly to database tables.
- Entity Manager – Once mappings are defined, the Entity Manager manages your entities and handles all interactions with the database.
- JPQL (Java Persistence Query Language) – Provides a way to write queries against entities. Unlike SQL, JPQL understands the mappings between entities and tables, allowing you to add conditions as needed.
- Criteria API – Offers a Java-based API to build and execute queries programmatically against the database.
JPA vs Hibernate
Hibernate is one of the most popular ORM frameworks.
JPA defines the specification and provides an API, answering key questions like:
- How do you define entities?
- How do you map attributes?
- How do you map relationships between entities?
- Who manages the entities?
Hibernate is a widely used implementation of JPA:
- It understands the mappings defined between objects and database tables, ensuring that data is stored and retrieved correctly.
- Hibernate also offers additional features beyond JPA. However, relying on these features creates a vendor lock-in, making it difficult to switch to other JPA implementations such as TopLink.
Examples of JPA Mappings
Let’s look at a few examples to understand how JPA can be used to map objects to database tables.
Example 1
Suppose we have a Task class that we want to map to a Task table. There may be differences in column names between the class and the table. JPA provides annotations to handle this mapping:
@Table(name = "Task")– Maps the class to the database table.@Id– Marks the primary key of the entity.@GeneratedValue– Specifies that the primary key value will be generated automatically.@Column(name = "description")– Maps the class attribute to a specific column in the table.
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.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 differently than relationships between database tables.
For example:
- Each
Employeecan have multipleTasks. - Each
Taskcan be associated with multipleEmployees.
This creates a many-to-many relationship, which can be mapped in JPA using the @ManyToMany annotation.
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 need to be mapped to a single table, or a single class needs to be mapped across multiple tables.
In such cases, we define an inheritance strategy.
For example, the strategy InheritanceType.SINGLE_TABLE maps an entire class hierarchy to a single database table.
@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.

As shown in the image above, follow these steps to create your Spring Boot project:
- Launch Spring Initializr: http://start.spring.io/
- Set Group to
com.in28minutes.springboot - Set Artifact to
H2InMemoryDbDemo - Add the following dependencies:
- Web
- JPA
- H2 – an in-memory database used for this example
- Set Group to
- Click the Generate button at the bottom of the page.
- Import the generated project into Eclipse.
Project Structure
- H2InMemoryDbDemoApplication.java – Spring Boot launcher that initializes Auto Configuration and the Application Context.
- application.properties – Application configuration file.
- H2InMemoryDbDemoApplicationTests.java – Simple launcher for unit testing.
- pom.xml – Includes dependencies for Spring Boot Starter Web and Data JPA, and uses Spring Boot Starter Parent as the parent POM.
Important dependencies are listed 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>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-h2console -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-h2console</artifactId>
<version>4.0.0-M1</version> // you can it in if you're creating a Spring Boot application
</dependency>
User Entity
Let’s define a bean user and add the appropriate JPA annotations.
package com.example.h2.user;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.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 Annotations and Concepts
@Entity– Specifies that the class is a JPA entity. Apply this annotation to the entity class.@NamedQuery– Defines a static, named query in Java Persistence Query Language (JPQL).@Id– Marks the primary key of an entity.@GeneratedValue– Specifies how the primary key value should be automatically generated.protected User()– Default constructor required by JPA to instantiate the entity.
User Service to Interact with the Entity Manager
With JPA, it is common to create a service layer to interact with the Entity Manager.
In this example, we create a UserService to manage the persistence operations for the 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 Annotations and Concepts
@Repository– A Spring annotation indicating that this component is responsible for data access and interacting with a data store.@Transactional– A Spring annotation that simplifies transaction management.@PersistenceContext– Injects a persistence context, which manages a set of entities and tracks their states (e.g., managed, detached) in relation to the underlying database.EntityManager– The interface used to interact with the persistence context.entityManager.persist(user)– Makes theuserentity managed and persistent, i.e., saves it to the database.entityManager.createNamedQuery– Creates a TypedQuery to execute a JPQL named query. The second parameter specifies the expected result type.
An EntityManager instance is associated with a persistence context.
A persistence context is a set of entity instances in which each persistent entity identity corresponds to a unique entity instance.
Within this context, the lifecycle of entities is managed. The EntityManager API is used to create and remove persistent entities, find entities by their primary key, and execute queries over entities.
The set of entities managed by an EntityManager is defined by a persistence unit.
A persistence unit specifies all classes related or grouped by the application that must be mapped to a single database.
CommandLineRunner for User Entity Manager
The CommandLineRunner interface is used to indicate that a Spring bean should run as soon as the application context is initialized.
In this example, we execute a few simple methods on the UserService to demonstrate entity persistence and queries.
@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– TheUserServiceis automatically injected by Spring.- The remaining setup and configuration are straightforward.
Spring Data JPA
Spring Data JPA provides a consistent and simplified model for accessing data from different types of data stores.
The UserService we created earlier contains some redundant code that can be generalized. Spring Data JPA helps reduce boilerplate code and simplifies data access.
@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 key Spring Data modules to know:
- Spring Data Commons – Defines concepts that are shared across all Spring Data modules.
- Spring Data JPA – Provides easy integration with JPA repositories.
CrudRepository
CrudRepository is a core repository interface provided by Spring Data Commons.
It enables basic CRUD operations on a repository. Some important methods include:
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, provided by Spring Data JPA, is a JPA-specific repository interface that extends CrudRepository.
It offers additional JPA-related methods, such as flushing changes to the database and batch operations, while retaining all CRUD functionalities.
public interface JpaRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
We will now use JpaRepository to manage the User entity.
The key idea is to create a UserRepository that manages User entities, where the primary key is of type Long.
The snippet below highlights the important details for defining this repository.
package com.example.h2.user;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
User Repository: CommandLineRunner
The following code is straightforward. The CommandLineRunner interface indicates that this bean should run as soon as the Spring application context is initialized.
In this example, we execute a few simple methods on the UserRepository to demonstrate basic CRUD operations.
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– TheUserRepositoryis automatically injected by Spring.- The rest of the setup is straightforward.
H2 Console
Enable the H2 console in /src/main/resources/application.properties:
spring.h2.console.enabled=true
Start the application by running H2InMemoryDbDemoApplication as a Java application.
The H2-Console can also be accessed via the web browser.
- http://localhost:8080/h2-console
- Use db url jdbc:h2:mem:testdb
Questions
- Where was the database created?
- In memory, using H2.
- What schema is used to create the tables?
- Tables are created automatically based on the entity definitions.
- Where are the tables created?
- In memory, using H2, based on the entity definitions.
- Can I see the data in the database?
- http://localhost:8080/h2-console
- Use db url jdbc:h2:mem:testdb
- Where is Hibernate coming from?
- Provided by the Spring Data JPA Starter.
- How is a data source created?
- Automatically configured through Spring Boot Auto Configuration.
Spring Boot’s Magic with In-Memory Databases
- No project setup or additional infrastructure required.
- Zero configuration.
- Minimal maintenance.
- Easy to use for learning and unit testing.
- Simple to switch to a real database with minimal configuration.
Restrictions of Using In-Memory Databases
- Data is not persisted between application 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>4.0.0-M2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>21</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>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-h2console -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-h2console</artifactId>
</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>
/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 {
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 jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.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 jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import jakarta.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
spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER
spring.data.jpa.repositories.bootstrap-mode=default
spring.jpa.defer-datasource-initialization=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.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.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.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
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.junit.jupiter.SpringExtension;
import com.example.h2.user.UserRepository;
@DataJpaTest
@ExtendWith(SpringExtension.class)
public class UserRepositoryTest {
@Autowired
UserRepository userRepository;
@Autowired
TestEntityManager entityManager;
@Test
public void check_todo_count() {
assertEquals(3, userRepository.count());
}
}
