• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Thoughts on Java

  • Tutorials ▼
    • Hibernate & JPA Tutorials
    • Hibernate Tips
    • Tutorials on YouTube
  • Books & Courses ▼
    • Hibernate Tips Book
    • Online Training
    • Open Workshops
    • On-Site Training
  • Consulting ▼
    • Consulting Call
    • Project Coaching
  • About ▼
    • About Thoughts on Java
    • Support Thoughts on Java
    • Resources
  • Member Library
You are here: Home / Hibernate / Hibernate Advanced / Implementing the Repository pattern with JPA and Hibernate
Do you live in Europe?
Then I hope to see you at one of my in-person workshops in December 2019. You will learn to use Hibernate advanced features and to improve the performance of your persistence layer.

Implementing the Repository pattern with JPA and Hibernate

By Thorben Janssen Leave a Comment

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • email 


The repository pattern is extremely popular. In its modern interpretation, it abstracts the data store and enables your business logic to define read and write operations on a logical level. It does that by providing a set of methods to read, persist, update and remove an entity from the underlying data store.

 

Old vs. modern interpretation

If you read Patterns of Enterprise Application Architecture by Martin Fowler et al., you will recognize the difference to the initial goal of the repository pattern. Its main goal was the abstraction of the database access code. JPA already provides this abstraction. So, there is no need for another layer that provides the same functionality.

That’s why the new interpretation of the pattern now provides a higher level of abstraction and hides all specifics of the data store. That enables you to replace a data store with a completely different one, e.g., a relational database with a NoSQL database. But what’s even more important, all database access methods for an entity are defined in the same repository and not in different parts of the business logic. That makes the implementation of your business logic and reusing queries or other database operations much easier.



Already a member? Login here.

Explaining the repository pattern

The repository pattern is pretty simple. An interface defines the repository with all logical read and write operations for a specific entity. You can see an example of such a repository interface in the diagram.

The interface gets implemented by one or more classes that provide data store specific implementations of each interface method.

In my experience, it only rarely happens that you need to support more than one data store. So, you could argue that this pattern creates an overengineered persistence layer. But the interface abstraction also enables frameworks to generate huge parts of the required code.
 

Don’t want to read? You can watch it here!

Follow me on YouTube to not miss any new videos.

Implementing the repository pattern

In most enterprise projects, you only need to define the repository interfaces. Spring Data JPA and Apache DeltaSpike Data can generate standard repository implementations for you. You just need to provide your own implementation, if your implementation gets especially complex. I will show you more of that in the following articles of this series.

But for now, let’s implement the repository pattern without any frameworks. That makes the pattern easier to understand and highlights the benefits of frameworks that generate repetitive parts of the implementation.

 

Defining the repository interface

Let’s implement the same BookRepository interface as I showed you in the diagram. It defines 4 methods that you can use to:

  • save a new or changed entity (Please keep in mind that Hibernate detects and persists all changes of managed entities automatically. So, you don’t need to call the save method after you changed any entity attributes),
  • delete an entity,
  • find an entity by its primary key and
  • find an entity by its title.

 

package org.thoughts.on.java.repository;

import org.thoughts.on.java.model.Book;

public interface BookRepository {

	Book getBookById(Long id);

	Book getBookByTitle(String title);

	Book saveBook(Book b);
	
	void deleteBook(Book b);
}

 

Implementing the repository with JPA and Hibernate

In the next step, you can implement the BookRepository interface. In this example, I only create a simple JPA-based implementation, that doesn’t rely on any other frameworks.

package org.thoughts.on.java.repository;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import org.thoughts.on.java.model.Book;

public class BookRepositoryImpl implements BookRepository {

	private EntityManager em;
	
	public BookRepositoryImpl(EntityManager em) {
		this.em = em;
	}
	
	@Override
	public Book getBookById(Long id) {
		return em.find(Book.class, id);
	}

	@Override
	public Book getBookByTitle(String title) {
		TypedQuery<Book> q = em.createQuery("SELECT b FROM Book b WHERE b.title = :title", Book.class);
		q.setParameter("title", title);
		return q.getSingleResult();
	}

	@Override
	public Book saveBook(Book b) {
		if (b.getId() == null) {
			em.persist(b);
		} else {
			b = em.merge(b);
		}
		return b;
	}

	@Override
	public void deleteBook(Book b) {
		if (em.contains(b)) {
			em.remove(b);
		} else {
			em.merge(b);
		}
	}
}

If you ever called a JPQL query or persisted an entity in your business layer, the code of my repository implementation should look familiar. There is no big difference between implementing these operations in your business code or as part of a repository implementation.

In this example, the only noticeable difference is the implementation of the saveBook(Book b) method. You can call this method to persist a new entity or to merge an existing one. So, you need to detect if the method got called with a new or an existing entity. In this example, I let Hibernate generate the primary key values. So, the id attribute of all new entities should be null. If it isn’t null, it should be an existing entity which then gets merged into the persistence context.



Already a member? Login here.


 

Conclusion

The repository pattern is one of the most popular Java persistence patterns. It provides 2 main benefits:

  1. The pattern abstracts the data store and enables you to replace your data store without changing your business code.
  2. The repository improves the reusability of your persistence code, especially your queries, by encouraging you to implement all persistence operations in one place. That makes them easy to find and to reuse.

The implementation of the repository pattern is relatively simple. You need an interface that defines the persistence operations on a logical level. This interface gets implemented by one or more data store specific classes.

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • email 

Related posts:

  1. Unsynchronized PersistenceContext – How to model conversations with JPA
  2. 6 Hibernate features that I’m missing in JPA
  3. Mapping Definitions in JPA and Hibernate – Annotations, XML or both?
  4. Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
Become a Thoughts on Java Supporter to claim your member perks and to help me write more articles like this.

Filed Under: Hibernate Advanced, JPA

Improve Your Hibernate Skills At An In-Person Workshop

Implement Your Persistence Layer with Ease

Learn More About Hibernate

Need Some Help with Your Project?

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Join over 10.000 developers
in the
Thoughts on Java Library

Ebooks Sidebar Get free access to ebooks, cheat sheets and training videos.
Join Now!
Don't like ads?
Become a Thoughts on Java Supporter.
Special Launch Price

Let’s Connect


Thorben Janssen
Independent consultant, trainer and author
  • Facebook
  • GitHub
  • LinkedIn
  • Twitter
  • xing
  • YouTube

Speaking at

2nd-3rd December 2019
Düsseldorf (Germany):
Advanced Hibernate Workshop (2-day Workshop - English)

4th-6th December 2019
Düsseldorf (Germany):
Hibernate Performance Tuning Workshop (3-day Workshop - English)

Looking for an on-site training?

Featured Post

14 YouTube Channels You Should Follow in 2019

Getting Started With Hibernate

Entities or DTOs – When should you use which projection?

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Recent Posts

  • Don’t expose your JPA entities in your REST API
  • Hibernate Tip: How to control cache invalidation for native queries
  • Hibernate Tip: How to customize the association mappings using a composite key
  • Hibernate Tip: How to integrate an external query builder
  • Hibernate Tip: Best Way To Work with Scalar Projections
  • 6 Hibernate Mappings You Should Avoid for High-Performance Applications
  • Hibernate Tip: Best Way To Work with Scalar Projections
  • Using the Optimal Query Approach and Projection for JPA and Hibernate
  • Implementing the Outbox Pattern with CDC using Debezium
  • Hibernate Tip: Difference between @JoinColumn and @PrimaryKeyJoinColumn
Don't like ads?
Become a Thoughts on Java Supporter.

Copyright © 2019 Thoughts on Java

  • Impressum
  • Disclaimer
  • Privacy Policy