π[JAVA] JPAλ?
JPAλ?
νλ μΉ μν리μΌμ΄μ
μμ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€(RDB)
λ μ λ λΉ μ§ μ μλ μμμ΄λ€.
Oracle, MySQL, MsSQL λ±μ μ°μ§ μλ μΉ μ ν리μΌμ΄μ
μ κ±°μ μμμ λλ‘β¦
κ·Έλ¬λ€λ³΄λ κ°μ²΄λ₯Ό κ΄κ³ν λ°μ΄ν°λ² μ΄μ€μμ κ΄λ¦¬νλ κ²μ΄ λ§€μ° μ€μνλ€.
κ²°κ΅ νμ
νλ‘μ νΈμ λλΆλΆμ΄ μ ν리μΌμ΄μ
μ½λλ³΄λ€ SQL
μ΄ λ§μμ§κ² λμλ€.
μ΄μ λ RDBκ° SQLλ§ μΈμν μ μκΈ° λλ¬Έμ΄λ€.
κ·Έλμ κΈ°λ³Έμ μΈ CRUD
SQLμ λ§€λ² μμ±ν΄μΌνλ€.
μ΄λ° SQLμ λ§λλ λ¨μ 방볡 μ‘μ
λ μμ§λ§, ν¨λ¬λ€μ λΆμΌμΉ
λΌλ λ¬Έμ μ μ΄ μ‘΄μ¬νλ€.
RDBλ μ΄λ»κ² λ°μ΄ν°λ₯Ό μ μ₯ν μ§μ μ΄μ μ΄ λ§μΆ°μ§ κΈ°μ μ΄λ€.
λ°λλ‘ κ°μ²΄μ§ν₯ νλ‘κ·Έλλ° μΈμ΄λ λ©μμ§λ₯Ό κΈ°λ°μΌλ‘ κΈ°λ₯κ³Ό μμ±μ ν κ³³μμ κ΄λ¦¬νλ κΈ°μ μ΄λ€.
μ΄λ λ―, RDBμ κ°μ²΄μ§ν₯ νλ‘κ·Έλλ° μΈμ΄κ°μ ν¨λ¬λ€μ λΆμΌμΉ
κ° λ°μνλ€.
κ°μ²΄μ§ν₯ νλ‘κ·Έλλ°μμ λΆλͺ¨κ° λλ κ°μ²΄λ₯Ό κ°μ Έμ€λ €λ©΄ μ΄λ»κ² ν΄μΌν κΉ?
User user = findUser();
Group group = user.getGroup();
μμ κ°μ μ½λλ₯Ό μμ±νλ©΄ λλλ°, μ¬κΈ°μ λ°μ΄ν°λ² μ΄μ€λ₯Ό μΆκ°νλ©΄ μλμ κ°λ€.
User user = userDao.findUser();
Group group = groupDao.findGroup(user.getGroup());
μμ κ°μ΄ User, Group κ°κ° λ°λ‘ μ‘°ννκ² λλ€.
Userμ Groupμ΄ μ΄λ€ κ΄κ³μΈμ§ μ μ μμκΉ?
μμ, 1:N λ±μ λ€μν κ°μ²΄ λͺ¨λΈλ§μ λ°μ΄ν°λ² μ΄μ€λ‘ ꡬνν μ μλ€.
μ΄λ¬ν λ¬Έμ μ μ ν΄κ²°νκΈ° μν΄ λ±μ₯ν κ²μ΄ λ°λ‘ JPA
μ΄λ€.
κ·Έλμ JPAλ?
μλ‘ μ§ν₯νλ λ°κ° λ€λ₯Έ 2κ°μ μμμ μ€κ°μμ ν¨λ¬λ€μ μΌμΉ
λ₯Ό μμΌμ£ΌκΈ° μν κΈ°μ μ΄λ€.
μ¦, κ°λ°μλ κ°μ²΄μ§ν₯μ μΌλ‘ νλ‘κ·Έλλ°μ νκ³ , JPAκ° μ΄λ₯Ό RDBμ λ§κ² SQLμ λμ μμ±ν΄μ μ€ννλ€.
μ΄λ‘μ¨ νμ κ°λ°μλ κ°μ²΄μ§ν₯μ μΌλ‘ μ½λλ₯Ό μμ±νμ¬ SQLμ μ’
μμ μΈ κ°λ°μ νμ§ μμλ λλ€.
Spring Data JPA
JPA
λ μΈν°νμ΄μ€λ‘μ, μλ° νμ€λͺ
μΈμμ΄λ€.
μΈν°νμ΄μ€μΈ JPAλ₯Ό μ¬μ©νκΈ° μν΄μλ ꡬνμ²΄μΈ Hibernate
, EclipseLink
λ±μ΄ μλ€.
νμ§λ§, Springμμ JPAλ₯Ό μ¬μ©ν λλ μ΄ κ΅¬ν체λ€μ μ§μ λ€λ£¨μ§λ μλλ€.
ꡬν체λ€μ μ’ λ μ½κ² μ¬μ©νκ³ μ μΆμνμν¨ Spring Data JPA
λΌλ λͺ¨λμ μ¬μ©νλ€!
μ΄λ€μ κ΄κ³λ μλμ κ°λ€.
Spring Data JPA -> Hibernate -> JPA
μ₯μ 1: ꡬν체 κ΅μ²΄μ μ©μ΄μ±
ꡬν체 κ΅μ²΄μ μ©μ΄μ±
μ΄λ, Hibernate μΈμ λ€λ₯Έ ꡬνμ²΄λ‘ μ½κ² κ΅μ²΄νκΈ° μν¨μ΄λ€.
μ½κ² μκ°νλ©΄ Hibernateκ° μλͺ
μ λ€ν΄ μλ‘μ΄ JPA ꡬνμ²΄κ° λμΈλ‘ λ μ€λ₯΄κ² λ λ, Spring Data JPAλ₯Ό μ¬μ©νκ³ μλ€λ©΄ μ½κ² κ°μν μ μλ€.
μ€μ λ‘ μλ°μ Redis ν΄λΌμ΄μΈνΈκ° Jedisμμ Lettuceλ‘ λμΈκ° λμ΄κ° λ, Spring Data Redisλ₯Ό μ¬μ©ν μ μ λ€μ μ½κ² κ΅μ²΄λ₯Ό νλ€κ³ νλ€.
μ₯μ 2: μ μ₯μ κ΅μ²΄μ μ©μ΄μ±
λ°μ΄ν° νΈλν½μ΄ λ§μμ§ μλ‘ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€λ‘λ κ°λΉμ΄ μλ μ μλ€.
μ΄ λ MongoDBλ‘ κ΅μ²΄κ° νμνλ€λ©΄ κ°λ°μλ Spring Data JPAμμ Spring Data MongoDBλ‘ μμ‘΄μ±λ§ κ΅μ²΄νλ©΄ λλ€λ μ₯μ μ΄ μλ€.
μ¬μ©λ²
μ’ μμ± μΆκ°
[pom.xml]
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
[build.gradle]
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
μμ
[UserRepository]
public interface UserRepository extends JpaRepository<User, Long> {
// λ¨μ interface μμ±ν©λλ€.
// JpaRepository<>λ₯Ό μμ -> κΈ°λ³Έμ μΈ CRUD λ©μλ μλ μμ± (@Repository μΆκ° νμ μμ΅λλ€.)
// CRUD λ©μλ: findById, findAll, save, delete λ±...
}
public interface UserRepository extends JpaRepository<User, Long>
μ μλ―Έλ Spring Data JPAμμ μ 곡νλ
JpaRepository
μΈν°νμ΄μ€λ₯Ό νμ₯νμ¬ User μν°ν°(βUserβ)μ CRUD μμ
μ μννλ μΈν°νμ΄μ€λ₯Ό μ μΈνλ€λ μλ―Έμ΄λ€.
UserRepository
λ JpaRepository<User, Long>
μ νμ₯νκ³ μμΌλ©°, Generic νμ
μΌλ‘λ User
, κΈ°λ³Έ ν€μ νμ
μΌλ‘λ βLongβμ
μ§μ νκ³ μλ€.
μ£Όμ μ λ Έν μ΄μ
@Entity
ν
μ΄λΈκ³Ό λ§ν¬λ ν΄λμ€μμ λνλΈλ€.
κΈ°λ³Έκ°μΌλ‘ ν΄λμ€μ μΉ΄λ©μΌμ΄μ€μ μ΄λ¦μ μΈμ΄μ€μ½μ΄ λ€μ΄λ°(_)μΌλ‘ ν
μ΄λΈ μ΄λ¦μ 맀μΉνλ€.
- μ: SalesManager.java -> sales_manager table
Entity ν΄λμ€μλ μ λ setterλ©μλλ₯Ό λ§λ€μ§ μλλ€.
μ΄μ λ ν΄λΉ ν΄λμ€μ μΈμ€ν΄μ€ κ°λ€μ΄ μΈμ μ΄λμ λ³ν΄μΌ νλμ§ μ½λμμΌλ‘ λͺ
ννκ² κ΅¬λΆν μκ° μμ΄, μ°¨ν κΈ°λ₯ λ³κ²½ μ 볡μ‘ν΄μ§ μ μκΈ° λλ¬Έμ΄λ€.
λμ , ν΄λΉ νλμ κ° λ³κ²½μ΄ νμνλ©΄ λͺ
νν κ·Έ λͺ©μ κ³Ό μλλ₯Ό λνλΌ μ μλ 맀μλλ₯Ό μΆκ°ν΄μΌλ§ νλ€.
κ·Έλ¬λ©΄, μ΄λ»κ² λ°μ΄ν°λ² μ΄μ€μ κ°μ μ±μ μ½μ
ν κΉ?
μμ±μ λμ @Builder
λ₯Ό ν΅ν΄ μ 곡λλ λΉλ ν΄λμ€λ₯Ό μ¬μ©νλ©΄ λλ€.
@Id
ν΄λΉ ν μ΄λΈμ PK νλλ₯Ό λνλΈλ€.
@GeneratedValue
PKμ μμ± κ·μΉμ λνλΈλ€.
μ€νλ§λΆνΈ 2.0μμλ GenerationType.IDENTITY
μ΅μ
μ μΆκ°ν΄μΌλ§ SQLμμ PKμ λν΄ auto_increment
κ° μ μ©λλ€.
@Column
ν
μ΄λΈμ μΉΌλΌμ λνλ΄λ©° κ΅³μ΄ μ μΈνμ§ μλλΌλ ν΄λΉ ν΄λμ€μ νλλ λͺ¨λ μΉΌλΌμ΄ λλ€.
μ¬μ©νλ μ΄μ λ κΈ°λ³Έκ° μΈμ μΆκ°λ‘ λ³κ²½μ΄ νμν μ΅μ
μ΄ μμΌλ©΄ μ¬μ©νλ€.
@Column(length = 500, nullable = false)
private String name;
μμ μμμμλ @Column
μ length=500, nullable=false
μ΅μ
μ΄ μ μ©λμλ€.
length = 500
μ μλ―Έλ name λ³μμ μ΅λ κΈΈμ΄κ° 500μΌλ‘ μ ννλ€λ μλ―Έμ΄λ€.
SQLμμ varchar(500)
μΌλ‘ λ³Ό μ μλ€.
μ΄ λ, UTF-8 μΈμ½λ© κΈ°μ€μΌλ‘ νκΈμ ν κΈμλ₯Ό 3λ°μ΄νΈλ‘ νννκΈ° λλ¬Έμ μ½ 166μκ° κ°λ₯νλ€.
nullable = false
λ SQLμμ not null
μ μλ―Έλ‘ λ³΄λ©΄ λλ€.
μ¦, ν΄λΉ 컬λΌμ΄ nullκ°μ νμ©νμ§ μλλ€λ μλ―Έμ΄λ€.
μ΄λ κ² @Column(length = 500, nullable = false)
λ₯Ό μ¬μ©ν΄ νλμ μ»¬λΌ λ§€ν μ 보λ₯Ό μ§μ νλ©΄ JPAκ° ν΄λΉ νλλ₯Ό DBμ 컬λΌμΌλ‘ 맀νν λ μ΄ μ 보λ₯Ό μ°Έκ³ νμ¬
ν
μ΄λΈμ μμ±νκ±°λ μ
λ°μ΄νΈ νλ€.
μ΄λ₯Ό ν΅ν΄ DBμ μ€ν€λ§λ₯Ό κ΄λ¦¬νλ©΄μ νλμ μ μ½μ‘°κ±΄μ λͺ
μμ μΌλ‘ μ§μ ν μ μλ€.
@Builder
@Builder
λ Lombok λΌμ΄λΈλ¬λ¦¬μμ μ 곡νλ μ λ
Έν
μ΄μ
μ΄λ€.
μ΄λ₯Ό μ¬μ©νλ©΄ λΆλ³ κ°μ²΄λ₯Ό μμ±νλ λΉλ ν¨ν΄μ μλμΌλ‘ μμ±ν μ μλ€.
@Builder
μ λ
Έν
μ΄μ
μ ν΄λμ€ λ 벨μ μ μ©νλ©΄ ν΄λΉ ν΄λμ€μ λν λΉλ ν΄λμ€λ₯Ό μμ±νκ³ , μ΄ λΉλ ν΄λμ€λ₯Ό μ¬μ©νμ¬ κ°μ²΄ μμ± λ° μμ± κ°μ μ€μ νλ λ©μλ μ²΄μΈ νμμΌλ‘
ννν μ μλ€.
@Builderμ μ₯μ
- κ°λ
μ±μ΄ μ’μμ§λ€.
- κ°μ²΄ μμ± μμ
λ©μλ 체μΈ
νμμΌλ‘ μμ± κ°μ μ€μ ν μ μμ΄ κ°λ μ±μ΄ ν₯μλλ€.
- κ°μ²΄ μμ± μμ
- νμ μμ±μ λͺ
μμ μΌλ‘ ννν μ μλ€.
- λΉλ ν¨ν΄μμ νμλ‘ μ€μ ν΄μΌ νλ μμ±μ λͺ
μν μ μμ΄ κ°μ²΄μ
λΆλ³μ±
μ 보μ₯νλ€.
- λΉλ ν¨ν΄μμ νμλ‘ μ€μ ν΄μΌ νλ μμ±μ λͺ
μν μ μμ΄ κ°μ²΄μ
- μ νμ μμ±μ μ μ°νκ² μ€μ ν μ μλ€.
- μ νμ μΌλ‘ μ€μ ν μ μλ μμ±μ μ½κ² μΆκ°ν μ μλ€.
- μ νμ μΌλ‘ μ€μ ν μ μλ μμ±μ μ½κ² μΆκ°ν μ μλ€.
μμ
[UserUpdateRequestDto]
...
@Builder
public UserUpdateRequestDto(Long id, String name, String phone, String address) {
this.id = id;
this.name = name;
this.phone = phone;
this.address = address;
}
...
[UserControllerTest]
...
@Test
void update() {
// given
Long id = 3L;
String name = "update_test2";
String phone = "010-1111-1111";
String address = "suwon";
String url = "http://localhost:" + port + "/users/update/" + id;
UserUpdateRequestDto requestDto = UserUpdateRequestDto.builder()
.id(id)
.name(name)
.phone(phone)
.address(address)
.build();
// when
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(requestDto), String.class);
// then
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
...
μ°Έκ³ μλ£
κ΅μ¬: μ€νλ§λΆνΈμ AWSλ‘ νΌμ ꡬννλ μΉ μλΉμ€
λκΈλ¨κΈ°κΈ°