엔티티(Entity)
JPA에서 엔티티는 DB 테이블에 대응하는 하나의 클래스이다. 따라서 엔티티는 JPA를 사용하는 데 가장 중요한 것으로 엔티티와 테이블을 정확히 매핑해야 한다.
JPA는 다양한 매핑 어노테이션을 지원하는 데 크게 4가지가 있다.
- 객체와 테이블 매핑: @Entity, @Table
- 기본 키 매핑: @Id
- 필드와 컬럼 매핑: @Column
- 연관관계 매핑: @ManyToOne, @JoinColumn 등
먼저 @Entity로 엔티티를 정의하는 것과 @Id로 기본 키를 매핑하는 것을 알아보고 그 후 연관관계 매핑과 컬럼 매핑을 알아보자.
객체와 테이블 매핑(@Entity, @Table)
@Entity
JPA를 사용해서 테이블과 매핑할 클래스는 꼭 @Entity를 필수로 붙여야 한다.
@Entity가 붙은 클래스는 JPA가 관리하는 것으로 앞서 언급했던 JPA에서 가장 중요한 엔티티를 가리킨다.
@Entity
public class MovieEntity {
// 내용...
}
참고로 @Entity를 사용하여 JPA에서 사용하는 엔티티를 만들게 되면 name을 지정해줘야 하는데 기본 값으로 클래스의 이름이 적용된다. 만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 name 속성을 사용하여 충돌을 피할 수 있게 해줘야 한다.
@Entity를 사용할 때 주의할 점으로는
- 기본 생성자를 필수로 생성해야 한다.
- final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
- 저장할 필드에 final을 사용할 수 없다.
@Table
@Table 어노테이션은 엔티티와 매핑할 테이블을 지정해 준다.
만약 생략하게 된다면 매핑한 엔티티 이름을 테이블 이름으로 사용하게 된다.
기본 키 매핑(@Id)
JPA를 사용해서 @Entity를 통해 엔티티 클래스를 만들게 되면 기본 키를 꼭 설정해줘야 한다.
@Entity
public class MovieEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
@Id 어노테이션을 사용하여 기본 키를 할당할 수 있고 @GeneratedValue와 같이 여러 전략을 통해 키를 생성할 수 있다.
- IDENTITY: 기본 키 생성을 데이터베이스에 위임한다.
- SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다.
- TABLE: 키 생성 테이블을 사용한다.
DB에서 자주 사용하게 되는 기본 키 생성 전략 중에서 AUTO_INCREMENT는 IDENTITY 전략을 통해서 구현할 수 있다.
IDENTITY는 기본 키 생성을 데이터베이스에 위임하는 전략으로 데이터베이스가 자동으로 AUTO_INCREMENT 기능을 기본 키 생성할 때 적용해 준다.
JPA CRUD
JPA에서 데이터를 저장하기 위해 EntityManager가 필요하다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernateproject");
EntityManager em = emf.createEntityManager();
EntityManager를 사용하기 위해서는 먼저 EntityManagerFactory를 생성하여 EntityManager를 만들어줘야 하는데 이때 미리 설정해 둔 xml 파일을 통해서 EntityManagerFactory를 생성하게 된다.
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="hibernateproject">
<properties>
<property name="javax.persistence.jdbc.driver" value="DB드라이버"/>
<property name="javax.persistence.jdbc.user" value="DB 사용자 이름"/>
<property name="javax.persistence.jdbc.password" value="사용자 비밀번호"/>
<property name="javax.persistence.jdbc.url" value="DB주소/DB명"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
위의 코드는 persistence.xml 파일로 EntityManagerFactory가 해당 내용을 통해서 DB와 연결하고 각종 hibernate 설정을 하게 된다.
이렇게 생성된 EntityManagerFactory에서 EntityManager를 하나 생성하여 DB와 관련된 작업들을 수행할 수 있게 된다.
Create(Insert)
JPA를 사용하여 데이터 삽입이 어떻게 이뤄지는지 확인해 보자.
@Entity
public class User {
@Id
private String id;
private String name;
}
먼저 저장하고 싶은 객체를 생성해 준다.
위의 코드에서는 User 객체를 생성해 주고 test1이라는 이름을 저장하였다.
그런 다음에 entityManager의 persist() 메서드를 사용하는데 생성한 객체를 persist() 메서드의 매개변수로 전달하고 실행하면 해당 내용은 영속성 컨텍스트의 1차 캐시 저장소에 저장되고 INSERT 쿼리 문이 쓰기 지연 쿼리 저장소에 저장된다.
여기서 주의할 점은 영속성 컨텍스트에 해당 데이터가 있는 것으로 아직 DB서버에 적용되지 않았기 때문에 DB를 조회해도 데이터가 없다.
데이터를 DB에 저장하기 위해서는 commit() 메서드를 실행해야 쿼리 저장소에 있는 쿼리 문이 실행되면서 DB에 저장된다.
EntityTransaction et = em.getTransaction();
이때 entityManager에서 getTransaction()을 통해 트랜잭션을 가져와서 commit을 실행하게 된다.
트랜잭션을 실행하는 것이기 때문에 여러 쿼리문을 실행하고 commit을 통해 여러 작업을 한 번에 DB로 적용시킬 수도 있다.
commit이 끝나면 영속성 컨텍스트에 있던 정보들은 없어지게 된다.
Read(Select)
데이터를 조회하는 Read(Select)는 따로 commit 없이 데이터를 조회하게 된다.
조회를 할 때는 entityManager의 find() 메서드를 통해서 조회하게 되는데 이때 조회할 클래스와 id를 넘겨주게 된다.
만약 해당 데이터가 1차 캐시 저장소에 있다면 객체를 반환해 주게 된다.
하지만 만약 1차 캐시 저장소에 데이터가 없다면 DB서버에서 해당 데이터를 조회한다.
마지막으로 DB 서버에서 조회한 데이터를 1차 캐시 저장소가 반환받고 객체로 만들어서 다시 호출했던 메서드로 반환해 주게 된다.
Update(Update)
데이터를 갱신하는 Update는 조금 특이하게 동작한다.
먼저 find() 메서드를 통해서 1차 캐시 저장소에 해당 데이터가 있는지 조회하고 없다면 1차 캐시 저장소가 DB 서버에서 조회하게 된다.
DB에서 조회한 데이터를 반환받아 1차 캐시 저장소가 객체로 만들어주고 해당 객체를 다시 메서드 호출한 곳으로 반환하게 된다. 여기 까지는 데이터를 조회하는 부분과 같지만 이다음 작업부터 데이터 갱신이 이뤄지게 된다.
1차 캐시 저장소로부터 받은 객체에 setName()을 통해 데이터를 갱신해 주게 되면 1차 캐시 저장소에 있던 기존 데이터가 변경이 이뤄지고 쓰기 지연 쿼리 저장소에는 UPDATE 쿼리문이 저장되게 된다.
여기서 주의할 점으로는 find를 하면 데이터가 1차 캐시 저장소에 남아 있다는 점이다.
1차 캐시 저장소에 데이터가 있기 때문에 해당 데이터에 접근하여 데이터 변경을 할 수 있게 된다.
마지막으로 commit() 메서드를 실행하여 DB에 적용시켜 변경된 데이터를 저장하게 되고, 1차 캐시 저장소와 쓰기 지연 쿼리 저장소에서 해당 데이터가 없어지게 된다.
Delete(Delete)
delete도 update와 마찬가지로 find() 메서드를 통해 데이터를 먼저 1차 캐시 저장소에서 조회한다.
find() 메서드를 통해서 반환받은 객체를 entityManager의 remove() 메서드의 매개변수로 넘겨주고 실행시킨다.
remove()가 실행되면 1차 캐시 저장소에 있던 데이터는 삭제되고 쓰기 지연 쿼리 저장소에 DELETE 쿼리문이 저장된다.
마지막으로 commit() 메서드를 통해서 DB에 delete 작업을 반영하여 DB에서 해당 데이터를 삭제시킨다.
'JPA' 카테고리의 다른 글
JPA - ORM과 JPA (1) | 2023.12.29 |
---|