📢 오늘의 목표 📢
✔️ 알고리즘, SQL 문제 풀이
✔️ 알고리즘 코드카타
✔️ SQL 코드카타
✔️ 프로그래머스 Level 2
✔️ 스프링 강의 숙련 주차
✔️ 4주차 듣기
✔️ 스프링 개인 과제
⏱️ 오늘의 일정 ⏱️
9:00 ~ 10:00 - 알고리즘 코드 카타
10:00 ~ 12:30 - 스프링 숙련 강의 듣기
13:00 ~ 14:00 - 점심시간
14:00 ~ 18:00 - 스프링 숙련 강의 듣기
18:00 ~ 19:00 - 저녁 시간
19:00 ~ 20:00 - 스프링 개인 과제
20:00 ~ 21:00 - TIL 작성
📜 Chapter 1. 알고리즘 코드 카타
CodingTest_AutoSave/프로그래머스/1/70128. 내적 at main · MetroDefro/CodingTest_AutoSave
모든 코딩 테스트 자동 저장. Contribute to MetroDefro/CodingTest_AutoSave development by creating an account on GitHub.
github.com
CodingTest_AutoSave/프로그래머스/3/144855. 카테고리 별 도서 판매량 집계하기 at main · MetroDefro/
모든 코딩 테스트 자동 저장. Contribute to MetroDefro/CodingTest_AutoSave development by creating an account on GitHub.
github.com
📜 Chapter 2. 스프링 숙련 강의 듣기 3주 차
✔️ 4-6 Entity 연관 관계
DB에서는 테이블 간에 방향이 없지만 Entity에서는 방향이 존재한다. 테이블 간에는 외래키로 join을 할 수 있기 때문. 대신 Entity 내에 다른 테이블을 참조하는 필드를 두어 조회하는 것이다. 여기서는 일대다(one to many) 관계를 표현하기 위해 컬렉션을 사용할 수도 있다. 만약 참조하는 필드를 두고 있지 않다면 조회가 불가능 해지기 때문에 이는 단방향이 된다.
✔️ 4-7 1대 1 관계
@OneToOne
단방향
외래 케의 주인만 외래 키를 등록, 수정, 삭제 할 수 있다.
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
}
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
외래 키의 주인이 @JoinColumn으로 외래 키를 등록한다. 상대 Entity를 필드에 저장하고 PK 이름을 입력
양방향
상대 Entity에서 외래 키의 주인을 지정해 줄 때 mappedBy 옵션을 사용한다. 외래 키의 주인인 상대 Entity의 필드명을 의미한다.
외래 키의 주인 Entity는 단방향과 동일. 1대 1 관계에선 @JoinColumn 애너테이션을 생략해도 되나 1대 다 관계에선 JPA가 중간 테이블을 생성해 버리기 때문에 애너테이션을 입력하는 습관을 들이는 것이 좋음.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(mappedBy = "user")
private Food food;
}
mappedBy = "user"에서 user는 외래 키의 주인인 상대 Entity의 필드명.
✔️ 4-8 N대 1 관계
@ManyToOne
단방향
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
@ManyToOne 애너테이션으로 다대1관계라는 걸 명시한다.
양방향
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user")
private List<Food> foodList = new ArrayList<>();
}
상대 Entity는 One인 쪽이기 때문에 @OneToMany 애너테이션을 사용한다.
또한 컬렉션을 사용해 Many인 쪽을 참조하고 있다.
✔️ 4-9 1대 N 관계
@OneToMany
단방향
Entity에서는 1인 쪽이 외래키의 주인이더라도 데이터 베이스에는 상대 테이블이 fk를 가지고 있다.
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany
@JoinColumn(name = "food_id") // users 테이블에 food_id 컬럼
private List<User> userList = new ArrayList<>();
}
@JoinColumn을 가지고 있으나 외래키의 주인.
그러나 데이터베이스에서 외래키를 상대가 가지고 있기 때문에 users 테이블의 food_id 외래키를 적는다.
자신이 가진다기 보단 주도권을 갖는 쪽이라 보는 것이 좋겠다.
양방향
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "food_id", insertable = false, updatable = false)
private Food food;
}
일반적으로 양방향 관계가 존재하지 않음.
mappedBy 속성 제공하지 않음. 그러나 비슷하게 표현을 할 수는 있음. JoinColumn 어노테이션에서 기능을 제한하면 됨.
✔️ 4-10 N대 M 관계
@ManyToMany
JPA에서 N:M 관계를 풀어내기 위해 중간 테이블을 생성한다.
단방향
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToMany
@JoinTable(name = "orders", // 중간 테이블 생성
joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
private List<User> userList = new ArrayList<>();
}
@JoinTable 애너테이션으로 테이블 이름, 외래키의 주인 엔티티에서 조인할 컬럼, 상대 엔티티에서 조인할 컬럼을 입력
양방향
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "userList")
private List<Food> foodList = new ArrayList<>();
}
양방향도 mappedBy 옵션으로 외래 키 주인 설정.
중간 엔티티 직접 생성
@Entity
@Getter
@Setter
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "food_id")
private Food food;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
중간 테이블이 외래키의 주인 역할을 한다.
@Entity
@Getter
@Setter
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany(mappedBy = "food")
private List<Order> orderList = new ArrayList<>();
}
@Entity
@Getter
@Setter
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user")
private List<Order> orderList = new ArrayList<>();
}
다른 엔티티들은 중간 엔티티를 통해 서로를 조회할 수 있다.
이는 양방향으로 건 것이고 상대 엔티티 리스트 필드를 없애면 단방향으로 써도 무방하다.
✔️ 4-11 지연 로딩
연관 관계의 엔티티를 가져올 때(FetchType)는 두 가지 옵션이 있는데
@ManyToOne의 기본 옵션은 즉시 가져오는 것(EAGER)이고
@OneToMany는 필요한 순간에 가져오는 것(LAZY)이다.
뒤가 Many일 경우 양이 많을 수 있기 때문에 지연 로직 하는 것.
지연 로딩된 엔티티의 데이터를 조회하고 싶을 때는 @Transactional이 적용되어 있어야 한다.
이도 영속성 컨텍스트의 기능 중 하나기 때문.
✔️ 4-12 영속성 전이
연관된 엔티티들의 작업이 한 번에 수행되게 하고 싶다. (cascade)
public enum CascadeType {
/** Cascade all operations */
ALL,
/** Cascade persist operation */
PERSIST,
/** Cascade merge operation */
MERGE,
/** Cascade remove operation */
REMOVE,
/** Cascade refresh operation */
REFRESH,
/**
* Cascade detach operation
*
* @since 2.0
*
*/
DETACH
}
✔️ 4-13 고아 Entity 삭제
orphanRemoval = true
연관된 Entity와 관계를 제거했을 때 자동으로 해당 객체를 사라지게 한다.
📜 Chapter 3. 스프링 숙련 개인 과제
원래는 강의를 다 듣고 하려고 했는데... 강의 듣는 게 너무 싫어서 1~4단계만 간단하게 구현해봤다.
@Builder
@Getter
@Entity
@Table(name = "comment")
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor
@AllArgsConstructor
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "contents", nullable = false, length = 500)
private String contents;
@Column(name = "user_id", nullable = false)
private String userId;
@ManyToOne
@JoinColumn(name = "schedule_id")
private Schedule schedule;
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@Transactional
public Comment update(String contents) {
this.contents = contents;
return this;
}
}
이번 댓글 엔티티에서는 일정 엔티티와 관계를 나타내는 부분이 추가됐다.
솔직히 CRUD를 작성하는 거라 딱히 이전과 다른 부분은 없었다.
예외처리도 메서드마다 하는 건 솔직히 번거로워 보여서 이전과 같은 핸들러 방식 사용
신경 쓰였던 건 user id 부분인데 나중에 로그인, 회원가입 기능을 넣으면 지금 로직을 갈아 엎어야 할 것 같아서...
5~7단계 공통 조건은 일단 Validation을 계속 사용하고 있었으니 넘어가도 될 것 같고, 로그인 구현 후 나머지를 만들자.
그리고 아무리 봐도 5단계는 6, 7 단계를 하면서 같이 구현해야 하는 부분 같아서 일단 6단계부터 들어가기로 했다.
🌙 오늘을 마치며 🌙
'공부 기록 > 내배캠Java_5기' 카테고리의 다른 글
[내배캠][TIL] 30일 차 - 화요일, 과제 중 (0) | 2024.05.28 |
---|---|
[내배캠][TIL] 28일 차 - 금요일, 스프링 시큐리티를 다시 알아보자. (0) | 2024.05.24 |
[내배캠][TIL] 25일 차 - 화요일, 숙련 주차 시작! (0) | 2024.05.21 |
[내배캠][TIL] 24일 차 - 월요일 (0) | 2024.05.20 |
[내배캠][TIL] 23일 차 - 금요일, 수준별 수업 전부 듣기 (0) | 2024.05.17 |