JPA ๊ตฌํ์ฒด๋ก ํ์ด๋ฒ๋ค์ดํธ๋ฅผ ์ฐ์ ๋ค๋ฉด ์ฃผ์ํด์ผ ํ ์ ์ด ์์ต๋๋ค.
์ฝ๋๋ฅผ ๋ณด๋ฉฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ฌธ์ ๊ฐ ๋๋ ์ํฉ์ ๊ฐ๋ตํ ์ฝ๋๋ก ๋ํ๋ด์ด ๋ณด๊ฒ ์ต๋๋ค.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "member")
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public void setTeam(Team team) {
this.team = team;
}
}
Team์ Member๋ฅผ ์ฌ๋ฌ๊ฐ ๊ฐ์ง ์ ์์ต๋๋ค.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "team")
public class Team {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "team_id")
private Long id;
public String name;
public void setName(String name) {
this.name = name;
}
public void fieldLogic(){
System.out.println(this.name);
}
public void methodLogic(){
System.out.println(this.getName());
}
}
ํ ์คํธ๋ฅผ ์ํด name์ public์ผ๋ก ์ค์ ํ์์ต๋๋ค.
๋ฌธ์ ๊ฐ ๋๋ ์ฝ๋
Member member = new Member();
Team team = new Team();
team.setName("ํ์ด๋ฆ");
member.setTeam(team);
em.persist(team);
em.persist(member);
em.flush();
em.clear();
Member find = em.find(Member.class, member.getId());
System.out.println("=========ํ๋ ์ ๊ทผ========");
System.out.println(find.getTeam().name);
์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ค์ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
์์ธ
ํ์ด๋ฒ๋ค์ดํธ์์๋ Lazy Loading์ผ๋ก ์ค์ ๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง ๊ฐ์ฒด์ ๋ํด์๋,
ํ๋๊ฐ ๋ชจ๋ Null๋ก ์ค์ ๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค๊ณ ํฉ๋๋ค.
(EAGER ํน์ fetch join์ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ ์ค์ ๊ฐ์ฒด๊ฐ ๋ฐ๋ก ๋ฐํ๋๋ฏ๋ก ์ด๋ฌํ ์์ธ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.)
์ด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ํ๋๊ฐ ์๋ getter ๋ฑ์ ๋ค๋ฅธ public ํน์ protected ๋ฉ์๋๋ฅผ ํตํด ์ ๊ทผํ์ฌ์ผ ํฉ๋๋ค.
(private ํน์ package-private ๋ฉ์๋๋ก ์ ๊ทผํ๋ ๊ฒฝ์ฐ ์ฌ์ ํ ์ด๊ธฐํ๋์ง ์์ต๋๋ค)
์์ ์ฝ๋๊ฐ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ๋ค์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
Member find = em.find(Member.class, member.getId());
System.out.println("========ํ๋ ๋ฉ์๋ ์ ๊ทผ=========");
find.getTeam().fieldLogic();
์์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ง์ฐ๋ก๋ฉ ๊ฐ์ฒด๋ฅผ ์ค์ ์กฐํํ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
์๋ ๋ฉ์๋๋ค๋ ๋์ผํ๊ฒ ์๋ํฉ๋๋ค.
Member reference = em.find(Member.class, member.getId());
System.out.println("==========๋ฉ์๋ ๋ฉ์๋ ์ ๊ทผ=======");
reference.getTeam().methodLogic();
Member reference = em.find(Member.class, member.getId());
System.out.println("========== ๋ฉ์๋ ์ ๊ทผ=======");
System.out.println(reference.getTeam().getName());
์ฃผ์์
์ง์ฐ๋ก๋ฉ๋ ๊ฐ์ฒด๋ฅผ ์ค์ ์กฐํํ์๋๋ผ๋, ํด๋น ๊ฐ์ฒด์ ํ๋๋ ๋ชจ๋ null์ ๋๋ค.
์์ ์ฝ๋์ ๋๋ค.
Member member = new Member();
Team team = new Team();
team.setName("๋ณ๋ช
");
member.setTeam(team);
em.persist(team);
em.persist(member);
em.flush();
em.clear();
Member find = em.find(Member.class, member.getId());
System.out.println("========ํ๋ ๋ฉ์๋ ์ ๊ทผ=========");
find.getTeam().fieldLogic();
System.out.println(find.getTeam().name);
๋ค์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ค์ ๋ก ํ๋๋ฅผ public์ผ๋ก ์ด์ด์ ์ฌ์ฉํ๋ ์ผ์ ์๊ธฐ ๋๋ฌธ์ ๋ฑํ ๋ฌธ์ ๋ ์ผ์ ์๊ธฐ์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ฌ๋ ์ ์ ๊ฒฝ์ฐ์๋ ์๊ธฐ ์์ ์ ๋ํ @ManyToOne ๊ด๊ณ๋ฅผ ์ค์ ํ ํด๋์ค์์ ์ด๋ฌํ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค
์ ์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์์ต๋๋ค.
@Service
@RequiredArgsConstructor
@Transactional
public class CommentServiceImpl implements CommentService{
private final CommentRepository commentRepository;
@Override
public void remove(Long id) throws Exception {
Comment comment = commentRepository.findById(id).orElseThrow(() -> new Exception("๋๊ธ์ด ์์ต๋๋ค."));
List<Comment> removableCommentList = comment.findRemovableList();//์ฌ๊ธฐ๋ถ๋ถ!!!!!
removableCommentList.forEach(removableComment -> commentRepository.delete(removableComment));
}
}
List<Comment> removableCommentList = comment.findRemovableList();
ํด๋น ๋ฉ์๋์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.
ํด๋น ๋ฉ์๋๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์์ต๋๋ค.
public class Comment extends BaseTimeEntity {
...
private String content;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "parent_id")
private Comment parent;
public List<Comment> findRemovableList() {
Optional<Comment> parent = Optional.ofNullable(this.parent);
List<Comment> result = new ArrayList<>();
parent.ifPresentOrElse(
parentComment ->{
if( parentComment.isRemove()){//์ด๋ถ๋ถ ์ค๋ฅ ๋ฐ์
//๋ก์ง
}},
() -> {}
);
return result;
}
private boolean isRemove() {
return content.equals(REMOVE_MESSAGE);
}
}
isRemove์ ๋ฉ์๋์์ content is null์ด๋ผ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.
๋ถ๋ช content๋ null์ด ์๋์์์๋ ๋ถ๊ตฌํ๊ณ , ๋๋ฒ๊น ์ ํด๋ณด์๋๋ฐ ๊ฐ์ด ๋ค์ด๊ฐ์ง ์์์ต๋๋ค.
์ด๋ ์ญ์ content ๋์ getContent()๋ฅผ ์ฌ์ฉํ๋ฉด ํด๊ฒฐ๋ฉ๋๋ค.
๊ฐ์ ๋ฐ๊พธ๋ ๊ฒฝ์ฐ
Member ํด๋์ค์ ๋ค์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.
public void changeTeamName() {
System.out.println("ํ ์ด๋ฆ ๋ณ๊ฒฝํฉ๋๋น");
this.team.name = "ํ ์ด๋ฆ ๋ณ๊ฒ
";
}
๊ทธ๋ฆฌ๊ณ ๋ค์ ํ ์คํธ์ฝ๋๋ฅผ ์คํํ๋ฉด
Member member = new Member();
Team team = new Team();
team.setName("ํ์ด๋ฆ");
member.setTeam(team);
em.persist(team);
em.persist(member);
em.flush();
em.clear();
Member find = em.find(Member.class, member.getId());
find.changeTeamName();
em.flush();
em.clear();
find = em.find(Member.class, member.getId());
System.out.println(find.getTeam().getName());
๋ณ๊ฒฝ๋์ง ์์ ๊ฒ์ ์ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ๋ด๋ถ์์ ์ ๊ทผํ๋ฉด ์ด๋ ๋ฌ๋ผ์ง๋๋ค.
Member์ ๋ค์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public void changeTeamNameByMethod() {
this.team.changeName();
}
Team์๋ ๋ค์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public void changeName() {
this.name= "๋ฐ๊พผ๋ค์์";
}
๋ค์ ์ฝ๋๋ฅผ ์คํํฉ๋๋ค.
Member member = new Member();
Team team = new Team();
team.setName("ํ์ด๋ฆ");
member.setTeam(team);
em.persist(team);
em.persist(member);
em.flush();
em.clear();
Member find = em.find(Member.class, member.getId());
find.changeTeamNameByMethod();
em.flush();
em.clear();
find = em.find(Member.class, member.getId());
System.out.println(find.getTeam().getName());
์ฑ๊ณตํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ ํ ์ฐธ์กฐ๋ ์ด๋จ๊น์?
์ ํ ๊ณ์ธต๊ตฌ์กฐ ๊ฐ ๋ณ๊ฒฝ์ ๊ฒฝ์ฐ
@Getter
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Entity
@Table(name = "member")
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Member parent;
private String name;
public void setName(String name) {
this.name = name;
}
public void setId(long id) {
this.id = id;
}
public void setParent(Member parent) {
this.parent = parent;
}
public void changeParentNameV1(){
this.parent.name = "๋ถ๋ชจ ์ด๋ฆ ๋ณ๊ฒฝV1";
}
public void changeParentNameV2(){
getParent().name = "๋ถ๋ชจ ์ด๋ฆ ๋ณ๊ฒฝV2";
}
public void changeParentNameV3(){
this.parent.setName("๋ถ๋ชจ ์ด๋ฆ ๋ณ๊ฒฝ V3");
}
}
Member child = new Member();
Member parent = new Member();
parent.setName("๊ธฐ์กด");
child.setParent(parent);
em.persist(child);
em.persist(parent);
em.flush();
em.clear();
Member find = em.find(Member.class, child.getId());
find.changeParentNameV1();
em.flush();
em.clear();
find = em.find(Member.class, child.getId());
System.out.println(find.getParent().getName());
๊ฒฐ๋ก ์ ๋ฐ๋์ง ์์ต๋๋ค.
V2 ์ญ์ ๋์ผํฉ๋๋ค.
๊ทธ๋ฌ๋ V3์ ๊ฒฝ์ฐ ๋ฌ๋ผ์ง ๊ฒ์ ์ ์ ์์ต๋๋ค.
๋น์ทํ ๋ฌธ์
์ด์ ๋น์ทํ ๋ฌธ์ ๋ก, ์คํ๋ง ๋น๊ณผ ํ๋ก์ ๊ด๋ จ๋ ๋ฌธ์ ์ ๋๋ค.
https://kim-jong-hyun.tistory.com/110
์์ฝํ์๋ฉด Target Class๋ฅผ Proxy๋ก ๋ํํ Bean์ด ์์ ๋, ํด๋น ํ๋ก์๋ ๋ฉ์๋์ ๋ํด์๋ง ์๋ํ๊ณ ํ๋์ ๋ํด์๋ ์ ์ฉ์ ํ์ง ์๋๋ค๋ ๊ฒ์ ๋๋ค.
'๐๏ธ Spring > JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] ์ด๋ ค์ฃผ์ธ์ (2) | 2022.03.14 |
---|---|
[JPA] ์์ธ ์ข ๋ฅ์ ๋ฐ๋ฅธ ํธ๋์ญ์ ๋กค๋ฐฑ์ฒ๋ฆฌ (Checked Exception๊ณผ Unchecked Exception) (0) | 2022.01.22 |
[JPA] ํธ๋์ญ์ ์ ํ , ์ค์ฒฉ๋ ํธ๋์ญ์ (Transaction Propagation) (0) | 2021.12.27 |
[JPA] ๊ณ ๊ธ ์ฃผ์ - ์์ธ ์ฒ๋ฆฌ (0) | 2021.12.23 |
[JPA] ๋ฆฌ์ค๋ - ์ํฐํฐ์ ์๋ช ์ฃผ๊ธฐ์ ๋ฐ๋ฅธ ์ด๋ฒคํธ ์ฒ๋ฆฌ (3) | 2021.12.21 |