What is the difference between CrudRepository and JpaRepository
By default when I need to write a code to communicate with Repository I thought to use CrudRepository, but the JpaRepository also is an option, so should I review my bias?
1. Acronym
- CRUD — Create Retrieve Update Delete operation
- JPA — Java Persistence Api
- API — Application Program Interface
- IDE — Integrated Development Environment
2. Objective
Explain the difference between the interfaces CrudRepository and JpaRepository.
3. CrudRepository and JpaRepository
To explain the difference let’s see the diagrams of each one.
3.1. CrudRepository
From my point of view, the CrudRepository is the most used in tutorials/articles and does your work well.
3.2. JpaRepository
On the other hand, more complex, ie, allows you a fine grained control about your resource layer, so that’s great! 💪
In comparison with the CrudRepository this interface has important methods, such as findAll(Pageable)
findAll(Sort)
flush() and saveAndFlush(S).
but pay attention when your code is calling flush, since the Flush cleans the Hibernate first level cache.
Ok, but in terms of code performance, is it relevant? Yes, thinking about the client, your client needs all clients at once? What kind of client are expected? Using JpaRepository and using Pageable is easy to achieve those requirements.
4. Hands on
To make this article more interesting, let’s see a project that implements both interfaces and creates one Entity to store a Post in the simplest way.
4.1. Project
Below there is a project snapshot, find below the picture what each part does
Legend
1 — Post — Entity
2 — PostCrudRepository — Interface that extends the CrudRepository
3 — PostJpaRepository — Interface that extends the JpaRepository
4 — Menu — Class that serves the Menu options. This class communicates with the ui and the repos.
5 — AppMain — Startup (Boot) class marked as @SpringBootApplication
6 — application.yml — Application configuration file
7 — data.sql — used to populate the database on application startup
8 — schema.sql — used to create the database schema on application startup
9 — Test source folder
4.2. Class diagram
The diagram below shows the relationship between the entity and the repositories.
4.2.1. Post
This entity has few fields and a NamedQuery to find all posts by user and content text.
Notice that the NamedQuery is declared into PostCrudRepository. For convenience all customized methods are into PostCrudRepository, but could be into JpaCrudRepository as well.
package com.costa.luiz.twitter.model;
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.time.ZonedDateTime;
import java.util.UUID;
@Entity
@Table(name = "posts")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
@ToString
@NamedQuery(name = "Post.findAllByUserAndPost",
query = "select post from Post post where post.user = ?1 and post.content like CONCAT('%',?2,'%')")
public class Post {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator"
)
private UUID id;
private String user;
private String content;
@Column(name = "created_at")
private ZonedDateTime createdAt;
}
4.2.2. PostCrudRepository
This interface has some customized queries, and follow the Spring pattern, in order to just declared the method and Spring build the query.
Just to given more examples were created two coded methods: findAllByUserAndPost and countPostContentWithContentLowerCase.
package com.costa.luiz.twitter.model;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.time.ZonedDateTime;
import java.util.List;
@Repository
public interface PostCrudRepository extends CrudRepository<Post, String> {
List<Post> findAllByUser(String user);
List<Post> findAllByCreatedAtBetween(ZonedDateTime start, ZonedDateTime end);
List<Post> findAllByUserContains(String user);
//NamedQuery
List<Post> findAllByUserAndPost(String user, String post);
//Native Query
@Query(value = "SELECT count(1) FROM posts p WHERE lower(p.content) like CONCAT('%',?1,'%')", nativeQuery = true)
Long countPostContentWithContentLowerCase(String content);
}
4.2.3. PostJpaRepository
This is the interface PostJpaRepository, at this moment nothing customized here, but this interface is really powerful, let’s see this on the tests section.
package com.costa.luiz.twitter.model;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PostJpaRepository extends JpaRepository<Post, String> {
}
5. Tests
First of all, it is good practice to define a scenario 😉. For all tests, will be used the following configuration: application.yml, schema.sql, and data.sql
5.1. CrudRepository
Important to remember ❕Since JpaRepository extends CrudRepository, all the methods/test are valid to both.
5.2. JpaRepository
Now is where the difference emerges. The first one is the method deleteAllInBatch
where Spring will delete all and clean the first level cache, paying attention to not have side effects in this kind of operation.
The second one is using the PageRequest
object. Here was request the page 1 (index starts with 0), of size 2 and sorted by the field createdAt
On the other hand is possible to sort the response sending some fields, in this case createdAt
and user
6. Code
The complete code is available in my GitHub.
7. Run locally
To run this project locally you need the following softwares:
- Java 11
- Maven
7.1. Compile
mvn clean package -DskipTests
7.2. Run the app
java -jar target/crud_vs_jpa-0.0.1-SNAPSHOT.jar
After the application has been started, using the keyboard you can: (exit) Exit, (0) create a random post, (1) count the posts and (2) read all posts
8. Conclusion
It’s clear to me the benefit to have a pageable query, delete by batch and so on. Apart from the pageable query, when the project needs to flush the data either by performance problems or by database issues is a good point. In my articles from now on, I’ll adopt the JpaRepository 🙌.
If you like of this kind of content, leave your claps 👏 👏 👏