A lot of the tutorials and examples available online will create a custom repository
which will extends JpaRepository
. This customer repository will be used to interact with the database.
Most of the time this custome repository
will have no method, for example
package org.wesome.jpa.repository;
import com.sujan.example.jpa.entity.Apple;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AppleRepository extends JpaRepository<Apple, Long> {
}
most of the methods required are already defined in JpaRepository
, So the question arises
Do We Really Need to Create Custom Repository, Why Don't we Autowire JpaRepository Directly?
and the answer is
No We Don't Need to Create
Custom Repository
as long as we are not creating any custom method, We can AutowireJpaRepository
Directly
JpaRepository
provides most of the CRUD (Create, Read, Update and Delete)
methods. If applications have CRUD
operations only then JpaRepository
can be autowired directly.
Custome Repository
is required only when we need to create some custom methods which is not available in JpaRepository
.
drop database if exists AppleDb;
create database AppleDb;
use AppleDb;
create table apple (apple_id bigint not null, apple_name varchar(255), primary key (apple_id)) engine=InnoDB;
create table hibernate_sequence (next_val bigint) engine=InnoDB;
insert into hibernate_sequence values ( 1 )
package org.wesome.jpa.controller;
import org.wesome.jpa.entity.Apple;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AppleController {
@Autowired
private JpaRepository jpaRepository;
@GetMapping
Apple save() {
Apple apple = new Apple("Macintosh");
Apple save = jpaRepository.save(apple);
System.out.println("save = " + save);
return save;
}
}
package org.wesome.jpa.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@ToString
@Entity
@NoArgsConstructor
public class Apple {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long appleId;
private String appleName;
public Apple(String appleName) {
this.appleName = appleName;
}
}
package org.wesome.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
}
spring.datasource.url=jdbc:mysql://localhost:3306/AppleDb
spring.datasource.username=root
spring.datasource.password=root
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.sujan'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
select next_val as id_val from hibernate_sequence for update;
update hibernate_sequence set next_val= ? where next_val=?;
insert into apple (apple_name, apple_id) values (?, ?);
curl --location --request GET 'http://localhost:8080/'
If JpaRepository is used, How Spring Data JPA will map in which table entity will be saved?
Customer Repository
required two parameters while defining, T
and ID
. T
denotes the class for which repository will be configured and ID
denotes the data type of primary key of the entity class.
When we don't create any Custom Repository
and directly autowire the JpaRepository
, Spring Data JPA
identity the table name by @Table(name = "Apple")
configured in the entity class.
package org.wesome.jpa.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Entity
@Table(name = "Apple")
@ToString
@NoArgsConstructor
public class Apple {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long appleId;
private String appleName;
}
Should we ever create a custom repository then if all the required methods are provided in JpaRepository?
It depends on the context of the application, If a small POC or learning application needs to be created, all the required methods already available in JpaRepository
then autowiring the JpaRepository makes more sense since we don't need any custom methods..
If we need some custom methods for example native query, then creating a Custom Repository
makes more sense.
If the application will be deployed in production or there is a high probability that some new method will be required in the future, then always create Custom Repository
. If the current production code is using JpaRepository
and in between a custom method is required, then there will be a lot of code change required to incorporate this, a lot of places where JpaRepository
was used, needs to be updated, and this will require a throw testing. So in this case, it's always better to create a Customer Repository