μ λ΄μ©μ λ°νμΌλ‘ dbdiagram.ioλ₯Ό μ¬μ©ν΄μ ERDλ₯Ό μμ±νλ€.
ORM(Object Relational Mapping : κ°μ²΄ Objectμ κ΄κ³ν DBμ λ°μ΄ν°λ₯Ό μλμΌλ‘ Mapping ν΄μ£Όλ κ²)μ μΌμ’
κ°μ²΄ μ§ν₯μ μΌλ‘ νλ‘κ·Έλλ°μ νλ©΄, JPAκ° μ΄λ₯Ό κ΄κ³ν λ°μ΄ν°λ² μ΄μ€μ λ§κ² SQLμ λμ μμ±ν΄μ μ€νν¨.
JPAλ μΈν°νμ΄μ€λ‘ ꡬνμ²΄κ° νμν¨ - Hibernate, Eclipse Link λ±, νμ§λ§ Springμμ JPAλ₯Ό μ¬μ©ν λλ μ΄ κ΅¬ν체λ₯Ό μ§μ λ€λ£¨μ§λ μκ³ Spring Data JPAλΌλ λͺ¨λμ μ΄μ©ν¨ (JPA <- Hibernate <- Spring Data JPA)
Hibernate λμ Spring Data JPAλ₯Ό μ°λ μ΄μ ? -> ꡬν체 κ΅μ²΄μ μ©μ΄μ± (Hibernate μΈμ λ€λ₯Έ ꡬνμ²΄λ‘ μ½κ² κ΅μ²΄), μ μ₯μ κ΅μ²΄μ μ©μ΄μ± (κ΄κ³ν DB μ΄μΈμ λ€λ₯Έ μ μ₯μλ‘ μ½κ² κ΅μ²΄ - μλ₯Ό λ€μ΄ MongoDBλ‘ κ΅μ²΄κ° νμνλ€λ©΄ Spring Data JPAμμ Spring Data MongoDBλ‘ μμ‘΄μ±λ§ κ΅μ²΄νλ©΄ λλ€)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // jpa μΆκ°
runtimeOnly 'mysql:mysql-connector-java' // mysql
}
package com.clonecoding.instagrambackend.domain;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Getter
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
private String text;
@CreatedDate
private LocalDateTime createdAt;
private Long views = 0L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Image> images;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
@OneToMany(mappedBy = "post", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostLike> likes;
public Post() {}
@Builder
public Post(String text, User user, List<Image> images) {
this.text = text;
this.user = user;
this.images = images;
}
}
DB ν
μ΄λΈμ columnμ κ°κ° λ³μλ‘ μ§μ νλ€.
@OneToMany, @ManyToOne μΌλ‘ μ°κ΄ κ΄κ³λ₯Ό μ€μ ν΄μ€ μ μλ€.
package com.clonecoding.instagrambackend.domain;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByUser(User user);
@Query("SELECT count(c) from Post p join p.comments c where p.id = ?1")
Long countComments(Long id);
@Query("SELECT count(l) from Post p join p.likes l where p.id = ?1")
Long countLikes(Long id);
}
JpaRepositoryλ Dao κ°μ DB Layer μ κ·Όμλ‘ μΈν°νμ΄μ€λ‘ μμ±νλ€. λ¨μν μΈν°νμ΄μ€λ₯Ό μμ± ν, JpaRepository<Entity ν΄λμ€, PKνμ >μ μμνλ©΄ κΈ°λ³Έ CRUD λ©μλκ° μλμΌλ‘ μμ±μ΄ λλ€.
JpaRepositoryκ° μ 곡νμ§ μλ κΈ°λ₯μ μ¬μ©ν΄μΌ ν λλ μμ @Queryλ₯Ό μ°λ©΄ μνλ 쿼리λ₯Ό μ§μ ν΄μ€ μ μλ€.