Cascade = Entity의 상태변화를 전파하는 옵션
- Entity 에서 참조하는 다른 Entity 에 Entity 상태의 변화를 같이 전이시키는 것
- Account 엔티티 의 변화가 A -> B 로 갈 때 참조하는 Study 의 변화도 A -> B 로 변화하도록 전이시키는 것
- 기본 값은 "없음" 이다.
Entity 의 상태
- Transient : JPA 가 모르는 상태
- Persistent : Session.save() , 해당 Entity 를 영속화 하여 JPA 가 알고 있는 상태, 관리 중이며 데이터베이스에 insert 할 때에 일어난다. ( 1차 캐시 : PersistenceContext에 해당 Entity가 관리되는 경우 Entity 정보를 캐싱, 캐싱정보 사용 시 데이터베이스에 접근하지 않음 / Dirty Checking : JPA 에서 관리하는 Persistent 상태의 Entity 의 변경사항을 모니터링한다. / Write Behind : Entity 상태의 변화 값을 최대한 늦게 적용한다. [즉, Dirty Checking + Write Behind 를 사용하여 Entity 변화 값을 감지, 변경 값이 있을시 Update 문을 자동으로 실행 할 수 있게 되는 것] )
- Detached : JPA가 관리하지 않는 상태, 트랜잭션이 끝나 Entity 가 밖에서 사용 될 때를 의미 함. 다시 ReAttach 하기 위해서는 Session.update() , merge() , saveOrUpdate() 를 사용한다.
- Removed : JPA가 관리하고 있으나, 삭제하기로 한 상태이다. Session.delete() 사용, JPA가 관리 중이나 실제 commit 시 삭제가 일어난다.
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
//Transient 상태
Account account = new Account();
account.setUsername("Jungsoomin2");
account.setPassword("jpa");
Study study = new Study();
study.setName("spring data jpa");
account.addStudy(study);
Session session = entityManager.unwrap(Session.class);
//Persistent 상태.
session.save(account);
session.save(study);
// PersistenceContext 에 저장된 Entity 를 1차 캐싱하고 있기 때문에, 데이터베이스에서 Select 하지 않는다.!
Account loadAccount = session.load(Account.class, account.getId());
// Dirty Checking
loadAccount.setUsername("soominJung");
loadAccount.setUsername("soominJung2");
//Write Behind / PersistenceContext 저장하여 모니터링한 결과 값이 기존 Entity 정보와 동일하기 때문에 Update 문이 일어나지 않는다!.
loadAccount.setUsername("Jungsoomin2");
System.out.println("==========================================");
System.out.println(loadAccount.getUsername());
System.out.println("==========================================");
// return loadAccount; << Detached 상태
}
}
Persistent 상태, 1차 캐시, DirtyChecking + Write Behind 로 인해 Select 문 없이 Entity 정보가 출력 된 후 Insert 트랜잭션이 진행 됨
==========================================
soominJung
==========================================
Hibernate:
insert
into
account
(city, state, home_street, zip_code, created, password, username, yes, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
study
(name, owner_id, id)
values
(?, ?, ?)
Hibernate:
update
account
set
city=?,
state=?,
home_street=?,
zip_code=?,
created=?,
password=?,
username=?,
yes=?
where
id=?
Non-owning Entity 이자 부모테이블 인 Post. / Cascade 속성을 지정하지 않은 상태
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
@OneToMany(mappedBy = "post")
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
Owner Entity 이자 자식 테이블인 Comment
@Entity
public class Comment {
@Id @GeneratedValue
private Long id;
private String comment;
@ManyToOne
private Post post;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
두 테이블은 부모 자식 관계로 트랜젝션이 전파되어야 하는 관계에 있다.
Non-owning Entity 에서 맵핑 진행시 Owner Entity 에는 영속화 작업이 일어나지 않는다.
- "릴레이션이 부모 자식 관계가 아니다." 라는 뜻과 같다. 즉 각 Entity 는 독립적이다.
- 테이블이 부모 자식 관계를 가지고 있을 경우, 테이블에 변경사항이 전파되야하며, 이를 위해 cascade 속성을 사용하게 된다.
@Component
@Transactional
public class JpaParentChileRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Post post = new Post();
post.setTitle("Spring Data JPA 언제 보나.");
Comment comment = new Comment();
comment.setComment("빨리 보고 싶어요..");
post.addComment(comment);
Comment comment1 = new Comment();
comment1.setComment("곧 보여드릴게요.");
post.addComment(comment1);
Session session = entityManager.unwrap(Session.class);
session.save(post);
}
}
Hibernate:
select
nextval ('hibernate_sequence')
Hibernate:
insert
into
post
(title, id)
values
(?, ?)
datajpa=# select * from post;
id | title
----+----------------------------
8 | Spring Data JPA 언제 보나.
(1개 행)
datajpa=# select * from comment;
id | comment | post_id
----+---------+---------
(0개 행)
datajpa=#
부모자식 테이블의 트랜젝션 전파를 위한 Cascade 속성
양방향 관계를 설정하면서 cascade 속성을 주어 Persistent , remove 상태를 전파시키도록 선언.
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
// Entity 를 관리할 때 참조하는 Comment Entity 도 Persistent 상태로 관리해주렴.
@OneToMany(mappedBy = "post", cascade = {CascadeType.PERSIST,CascadeType.REMOVE})
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
자식 테이블로 영속화될 Comment = cascade 속성으로 인해 Post Entity 에 상태변화가 일어날 경우 멤버변수로 참조되고 있는 Comment Entity 도 상태가 전파 된다.
@Entity
public class Comment {
@Id @GeneratedValue
private Long id;
private String comment;
@ManyToOne
private Post post;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
DDL = 부모 테이블과 자식테이블에 insert 문이 모두 실행되는 상태.
Hibernate:
select
nextval ('hibernate_sequence')
Hibernate:
select
nextval ('hibernate_sequence')
Hibernate:
select
nextval ('hibernate_sequence')
Hibernate:
insert
into
post
(title, id)
values
(?, ?)
Hibernate:
insert
into
comment
(comment, post_id, id)
values
(?, ?, ?)
Hibernate:
insert
into
comment
(comment, post_id, id)
values
(?, ?, ?)
테이블 결과
datajpa=# select * from comment;
id | comment | post_id
----+--------------------+---------
2 | 곧 보여드릴게요. | 1
3 | 빨리 보고 싶어요.. | 1
(2개 행)
datajpa=# select * from post;
id | title
----+----------------------------
1 | Spring Data JPA 언제 보나.
(1개 행)
datajpa=#
CascadeType.REMOVE 전파 결과
@Component
@Transactional
public class JpaParentChileRunner implements ApplicationRunner {
@PersistenceContext
private EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Session session = entityManager.unwrap(Session.class);
Post post = session.get(Post.class, 1L);
session.delete(post);
}
}
DDL = 부모테이블과 자식테이블에 모두 delete 문이 실행되고 있음.
Hibernate:
delete
from
comment
where
id=?
Hibernate:
delete
from
comment
where
id=?
Hibernate:
delete
from
post
where
id=?
테이블 결과 = 부모자식 테이블 관계에 맞게 트랜잭션이 전파됨.
datajpa=# select * from comment;
id | comment | post_id
----+---------+---------
(0개 행)
datajpa=# select * from post;
id | title
----+-------
(0개 행)
datajpa=#
부모 - 자식 릴레이션 관계 설정 시 CascadeType.ALL 을 지정해서 전부 전파시키는 것이 일반적이다.
@Entity
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
// Entity 를 관리할 때 참조하는 Comment Entity 도 Persistent 상태로 관리해주렴.
@OneToMany(mappedBy = "post", cascade = {CascadeType.ALL})
private Set<Comment> comments = new HashSet<>();
public void addComment(Comment comment){
comments.add(comment);
comment.setPost(this);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Set<Comment> getComments() {
return comments;
}
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
'springframework > Spring Data JPA' 카테고리의 다른 글
Query (0) | 2020.11.13 |
---|---|
Fetch 전략 (0) | 2020.11.13 |
관계 맵핑, 1 : N (0) | 2020.11.13 |
Value 타입 맵핑 (0) | 2020.11.13 |
엔티티타입 맵핑 (0) | 2020.11.13 |