컴퓨터 공학에서 지속성(Persistence)은 프로세스가 생성했지만 별개로 유지되는 상태의 특징 중 한 가지이며, 별도의 기억 장치에 데이터를 보존하는 것을 목적으로 한다. 이 특징으로 인해 프로그래머는 저장 장치로부터 데이터를 전송하는 작업 및 자료 구조 등을 이용해 데이터를 보존하는 것이 가능하다.
이 특징 없이는 상태는 오직 RAM에만 존재할 수 있고, 컴퓨터가 종료되어 RAM이 전력을 잃어버린다면 상태도 같이 사라져 버리게 된다.
JPA를 공부하다보면, 아니 다른 프레임워크를 공부하거나 단순히 컴퓨터 공학 쪽을 공부를 하다 보면 영속성이란 단어를 접하게 됩니다.
저는 영속성이라는 속성을 다음과 같이 이해했습니다..!!
영속성이란 특정 데이터가 DB에 넣는 식으로 메모리가 아닌 디스크에 저장해 데이터를 저장될 때 얻는 속성!!
JPA는 그 이름에서부터 알 수 있듯이, 자바에서 영속성 관리할 수 있도록 도와주는 API 입니다!
그러면 JPA는 어떻게 객체의 영속성을 관리하는 걸까요??
그러기 위해서는 먼저 엔티티에 대해서 알아봐야 합니다!
Entities in JPA are nothing but POJOs representing data that can be persisted in the database. An entity represents a table stored in a database. Every instance of an entity represents a row in the table.
JPA에서의 엔티티는 데이터베이스에 영속되는 데이터를 표현하는 POJO(Plain Old Java Object) 입니다!!
즉 저장하고 싶은 객체를 RDB에 테이블 형태로 저장하고자 할 때, 해당 자바 객체를 Entity
라고 하는 것이죠.
그렇다면 엔티티를 등록하기 위해서는 어떻게 해야할까요??
바로 @Entity
어노테이션을 통해서 가능합니다!!
@Entity
@Table(name = "penguins")
@NoArgsConstructor
public class Penguin {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
private float length;
private float weight;
private Species species;
@Builder
public Penguin(Long id, String name, int age, float length, float weight, Species species) {
this.id = id;
this.name = name;
this.age = age;
this.length = length;
this.weight = weight;
this.species = species;
}
}
위와 같이 영속화를 하고자 하는 클래스에 @Entity
를 추가해 주는 것 만으로도 JPA의 도움을 받을 수 있죠
@Table
어노테이션은 해당 객체를 영속화 시키고자 하는 DB의 테이블을 입력하면 됩니다.
대부분의 경우에는 POJO 클래스의 이름과 RDB의 테이블은 일치하지 않으니까요
물론 ddl-auto 설정을 create로 설정할 경우에는 알아서 DB에 테이블을 생성해주지만.... 해당 옵션은 연습이나 개발 단계에서만 사용하기 때문에 문제가 생길 여지가 다분히 존재하죠!!
그렇기 때문에 원하는 테이블에 영속화 시키기 위해서는 해당 어노테이션을 사용주는 것이 좋습니다!!
JPA에서 제공하는 기능은 크게 엔티티-테이블 매핑을 하는 설계부분, 매핑한 엔티티를 실제로 사용하는 두 부분으로 나누어져있다고 볼 수 있습니다.
그 중에서 오늘 궁금한 부분은 바로 엔티티를 실제로 사용하는 부분입니다!!
엔티티를 저장하고, 수정하고, 삭제하는게 개발자가 해야 하는 일이니까요!!
그런데 실제로 이런 일을 수행하는 것은 누구일까요??
바로 엔티티 매니저(Entity Manager)입니다!!
말 그대로 엔티티의 관리자로서 엔티티의 CRUD 및 영속화를 하는데 도움을 주죠
개발자는 엔티티를 저장하는 가상의 DB로 생각해도 됩니다.
EntityManagerFactory
는 EntityManger
를 만들어주는 공장입니다!
보통 하나의 데이터 베이스를 사용할 경우 EntityMangerFactory
는 역시 하나만 생성합니다.
공장답게 해당 객체는 생성하는데 비용이 많이 들기 때문입니다!
그래서 하나만 생성하고, 어플리케이션 내에서 공유를 하게 됩니다.
대신 EntityManagerFactory
는 Thread Safe하다는 특성을 가지고 있습니다!!
생성 비용이 비싼 값을 하는군요!
EntityManger
를 생성해 주는 공장EntityManager
는 위의 EntityManagerFactory
로 부터 생성된 객체입니다.
EntityManagerFactory
와는 다르게 생성하는데 비용이 거의 들지 않죠!!
그리고 Entity
의 CRUD를 실질적으로 수행하는 역할을 담당하죠!!
실무자와 같은 포지션이네요!!
하지만 EntityManagerFactory
와는 다르게 멀티스레드 환경에 대해서 안전하지 않기 때문세
절대 스레드간에 공유를 하면 안됩니다!!!
그리고 EntityManager
들은 생성 되었더라도 DB 연결이 필요하지 않으면, 커넥션을 획득하지 않습니다!!
트랜잭션이 시작되거나 할 때와 같이 DB와의 연결이 필요지면 그때서야 커넥션 풀에서 커넥셔을 하나 가져와서 연결을 합니다!
Entity
CRUD를 담당하는 실무자 포지션EntityManagerFactory
로 생성 가능밑의 코드와 같이 생성합니다!!
참고로 해당 코드들은 스프링 프로젝트의 test 디렉토리 아래에서 테스트 환경 아래에서 작성되었습니다!
@SpringBootTest
class EntityApplicationTests {
@Autowired
EntityManagerFactory emf;
@Test
void contextLoads() {
EntityManager em = emf.createEntityManager();
}
}
그림으로 한 번 확인해보겠습니다!!
아마 인터넷에서 많이 보셨을 그림입니다ㅎㅎ
저는 김영한 님의 자바 ORM 표준 JPA 프로그래밍를 참고하면서 글을 작성하다보니 자연스럽게 해당 그림을 자료로 사용하게 되었는데
이해하는데 도움이 될 것같아서 가져왔습니다!!
위 그림을 보시면 지금까지의 나온 특성들이 잘 표현되어 있습니다.
EntityManagerFactory
EntityManager
를 생성함EntityManager
EntityManager
는 커넥션을 획득하지 않음JPA를 이해하는데 많은 사람들이 가장 강조하는 매우 중요한 요소입니다!!
간단히 말하자면, Entity를 영구히 저장하는 환경이란 뜻!!
EntityManager
는 영속성 컨텍스트에 Entity
를 저장합니다!!
역시 유명한 그림을 먼저 보겠습니다!!
Entity 생명주기
Entity는 총 4가지 생명 주기가 존재합니다.
각 상태에 대해서 자세히 알아보죠!!
저는 이 개념을 처음 이해하는데 매우 어려웠습니다..
그래서 저는 비유를 통해서 이해를 했는데요
그렇기 때문에 각 생명 주기에 대해서 제 나름대로 비유가 들어갈 예정입니다!!
해당 비유는 제 나름대로의 비유이므로, 오히려 헷갈릴 수 있기 때문에 참고만 하거나, 아예 이해가 안된다면 무시해주시면 감사하겠습니다!!
각 비유 대상은 다음과 같습니다
penguin | 영속성 컨텍스트 | EntityManager |
---|---|---|
유치원생 | 유치원 | 아이 부모 |
아직은 영속성 컨텍스트와 아무런 관련이 없는 그저 POJO 상태일 때의 상태입니다.
Penguin penguin = Penguin.builder()
.id(1L)
.age(3)
.length(140)
.name("핑구")
.species(Species.EMPEROR_PENGUINS)
.weight(30)
.build();
위와 같이 Penguin 객체를 하나 생성했습니다!!
하지만 위 객체는 아직 영속성 컨텍스트, JPA와는 아무런 관련이 아직 없습니다!!
그냥 평소에 하듯이 객체를 생성 했을 뿐이죠!!
누구세요??
아직은 서로에 대해 모른다
아이는 얼마 전 이 동네로 이사왔고 아직 유치원에 다니지 않는다
즉, 아이와 유치원은 서로의 존재에 대해 모른다
이제 엔티티 매니저를 통해 해당 객체를 영속화 해보겠습니다!!
@Test
void contextLoads() {
EntityManager em = emf.createEntityManager();
Penguin penguin = Penguin.builder()
.id(1L)
.age(3)
.length(140)
.name("핑구")
.species(Species.EMPEROR_PENGUINS)
.weight(30)
.build();
em.persist(penguin);
}
영속화 빔!!!
!!
안뇽!!
자! 이제 EntityManager
는 penguin을 영속화 시켰고, 영속성 컨텍스트안에서 관리하게 되었습니다!!
이렇게 POJO 객체를 persist()
시키는 방식 외에도
em.find()
를 통해 가져온 객체JPA가 가져왔으니 처음부터 영속성 컨텍스트 안에서 관리하겠다....
저는 이런 식으로 이해했습니다!
아이 부모는 아이를 유치원에 등록 하고자 해서
유치원에 등록시킨다
얘야 내일부터 유치원 가자!
네에!
어머 네가 오늘부터 오기로 한 아이구나!
네!!
이제부터 유치원은 아이를 관리한다.
영속 상태인 객체를 영속성 컨택스트에서 분리하면,
더 이상 영속성 컨텍스트가 관리하지 않으면 준영속 상태라고 합니다!
나와!!!
안녕!!
객체를 준영속 상태로 만드는 방법은
em.detach()
em.close()
em.clear()
등의 메소드를 사용하면 됩니다.
em.clear()
등의 메소드를 사용하면 영속성 컨텍스트가 초기화 되는데, 이때 영속성 컨텍스트가 관리하던 영속상태의 Entity
들은 준영속 상태가 됩니다
이제 집에 가자~
네 엄마~
아이 부모는 유치원에서 아이를 하원시킨다
이제 유치원은 더 이상 아이를 관리하지 않는다.
아이 부모에 의해 아이는 유치원에 더 이상 관리되지 않는 상태에 놓여져 있다.
그렇다고 EntityManager가 객체를 관라히지 않습니다!!!
비유적인 표현입니다!!
말 그대로 객체가 삭제된 상태입니다.
영속성 컨텍스트와 DB 모두에서 삭제를 시킵니다.
em.remove()
메소드로 삭제할 수 있습니다
내가 없어져 볼게
얍!
시간이 지나 부모는 다시 이사를 가네요...
이제 여기서 떠나는 군요ㅠㅠ
아이 부모는 아이를 데리고 이사를 갑니다
아이 부모에 의해 아이는 사라집니다....
나중에 인연이 되면 또 만날지도...?
오늘은 일단 다음에 대해서 알아봤습니다
Entity
EntityManager
EntityManagerFactory
Entity
생명주기다음에는 바로
사실 1차 캐시, 변경 감지 등의 진짜 중요한 내용인데... 너무 템포가 길어지는 것 같아 일단은 여기서 끊겠습니다!
ㅋㅋㅋㅋㅋ 비유가 찰떡입니다. 안뇽~