๐ฅ JPA๋ ๋ฌด์์ธ๊ฐ? ๊ทธ๋ฆฌ๊ณ @Entity
, @Id
, @GeneratedValue
์ ์ญํ
JPA๋?
- JPA(Java Persistence API)๋ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๊ฐ์ฒด(ํด๋์ค)์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ ๋งคํ์ ์ ์ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํ ํ์ค ์ธํฐํ์ด์ค์ ๋๋ค.
- ์ญํ :
- ๊ฐ์ฒด์ ํ ์ด๋ธ ๊ฐ์ ๋งคํ์ ์๋์ผ๋ก ์ฒ๋ฆฌ (ORM: Object-Relational Mapping).
- SQL ์์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉ ๊ฐ๋ฅ.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ ๋ฆฝ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ์ง์.
- ๊ตฌํ์ฒด: Hibernate, EclipseLink, OpenJPA ๋ฑ์ด ์์ผ๋ฉฐ, JPA๋ ์ด ๊ตฌํ์ฒด๋ค์ ์ํ ํ์ค์ ๋๋ค.
@Entity
์ญํ : ํด๋์ค๊ฐ JPA ์ํฐํฐ์์ ์ ์ธํฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ๊ณผ ๋งคํ๋ฉ๋๋ค.
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
}
์ ์ฝ๋์์ User
ํด๋์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ user
ํ
์ด๋ธ๊ณผ ๋งคํ๋ฉ๋๋ค.
@Id
์ญํ : Primary Key๋ก ์ฌ์ฉํ ํ๋๋ฅผ ์ง์ ํฉ๋๋ค. ์ํฐํฐ์ ๊ฐ ์ธ์คํด์ค๋ฅผ ๊ณ ์ ํ๊ฒ ์๋ณํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
@Entity
public class User {
@Id
private Long id; // Primary Key
}
id
ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ Primary Key๋ก ์๋ํฉ๋๋ค.
@GeneratedValue
์ญํ : Primary Key์ ๊ฐ์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค. ๋ค์ํ ์์ฑ ์ ๋ต์ ์ง์ํฉ๋๋ค.
์์ฑ ์ ๋ต:
GenerationType.AUTO
: JPA ๊ตฌํ์ฒด๊ฐ ์ ์ ํ ์ ๋ต์ ์ ํ.GenerationType.IDENTITY
: ๋ฐ์ดํฐ๋ฒ ์ด์ค์AUTO_INCREMENT
๊ธฐ๋ฅ ์ฌ์ฉ.GenerationType.SEQUENCE
: ๋ฐ์ดํฐ๋ฒ ์ด์ค์Sequence ๊ฐ์ฒด
์ฌ์ฉ.GenerationType.TABLE
: ํค ๊ฐ์ ์ ์ฅํ๋ ๋ณ๋์ ํ ์ด๋ธ ์ฌ์ฉ.
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ id
๋ ์๋์ผ๋ก ์ฆ๊ฐํ๋ ๊ฐ์ผ๋ก ์ค์ ๋ฉ๋๋ค.
์์ ์ฝ๋ ์ ์ฒด
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
JPA๊ฐ ์ ๊ณตํ๋ ์ฃผ์ ์ฅ์
- ์์ฐ์ฑ ํฅ์: ๋ฐ๋ณต์ ์ธ SQL ์์ฑ ์์ด CRUD ์์ ๊ฐ๋ฅ.
- ์ ์ง๋ณด์ ์ฉ์ด์ฑ: ๊ฐ์ฒด ์ค์ฌ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ฏ๋ก ๊ฐ๋ ์ฑ์ด ์ข์.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ ๋ฆฝ์ฑ: ํน์ DBMS์ ์ข ์๋์ง ์๊ณ , ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋์ผํ ์ฝ๋๋ก ๋์.
๋์ ์๋ฆฌ ์์ฝ
- JPA๊ฐ
User
์ํฐํฐ๋ฅผuser
ํ ์ด๋ธ์ ๋งคํํฉ๋๋ค. id
๋ Primary Key๋ก ์ค์ ๋๋ฉฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์๋ ์์ฑ๋ฉ๋๋ค.- SQL ์์ฑ ์์ด๋ ๋ฐ์ดํฐ ์ ์ฅ, ์กฐํ, ์ญ์ ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
๐ฅ @Id์ @GeneratedValue๊ฐ ์์์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋งคํ
1. @Id๊ฐ ์์์ ๋
JPA์์ @Id๋ Primary Key๋ฅผ ์ง์ ํ๋ ์ด๋ ธํ ์ด์ ์ ๋๋ค. ๋ง์ฝ @Id๊ฐ ์์๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค:
- Primary Key ๋ฏธ์ง์ ์ผ๋ก ์ธํด JPA๊ฐ ๋งคํ ๋ถ๊ฐ๋ฅ: JPA๋ ์ํฐํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ด๋ค ๋ ์ฝ๋์ ๋งคํํ ์ง Primary Key๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋จํฉ๋๋ค. @Id๊ฐ ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์๋ฌ ๋ฉ์์ง:
javax.persistence.PersistenceException: No identifier specified for entity: com.example.User
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ด๋ฏธ Primary Key๊ฐ ์ค์ ๋์ด ์์ด๋, JPA๋ ์ด๋ฅผ ์ธ์ํ์ง ๋ชปํ๊ณ ๋ช ์์ ์ผ๋ก @Id๋ฅผ ์๊ตฌํฉ๋๋ค.
2. @GeneratedValue๊ฐ ์์์ ๋
Primary Key์ ์๋ ์์ฑ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. Primary Key ๊ฐ์ ๊ฐ๋ฐ์๊ฐ ์ง์ ๊ด๋ฆฌํด์ผ ํ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ต๋๋ค:
- ์๋ ์ฆ๊ฐ ๊ธฐ๋ฅ ์์ค: ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ Primary Key๋ฅผ ์๋์ผ๋ก ์ฆ๊ฐ์ํค์ง ๋ชปํ๋ฏ๋ก, ์ํฐํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ ์ Primary Key ๊ฐ์ ์๋์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
- Primary Key ๋๋ฝ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฌ: Primary Key ๊ฐ์ด ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ์ฝ ์กฐ๊ฑด ์๋ฐ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์์ ์ฝ๋ (Primary Key ๊ฐ ์๋ ์ค์ ):
@Entity public class User { @Id private Long id; // Primary Key๋ฅผ ์ง์ ์ค์ ํด์ผ ํจ private String name; } // ๋ฐ์ดํฐ ์ ์ฅ ์ User user = new User(); user.setName("Alice"); user.setId(1L); // Primary Key๋ฅผ ์๋์ผ๋ก ์ค์ entityManager.persist(user); // ์ ์ ๋์
- Primary Key๋ฅผ ์๋์ผ๋ก ์ค์ ํ์ง ์์ผ๋ฉด ์๋ฌ ๋ฐ์:
org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save()
3. ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋งคํ๋ ๊ฒฐ๊ณผ
Primary Key๊ฐ ์๊ฑฐ๋ ์๋ ์์ฑ๋์ง ์๋ ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค:
- ์ค๋ณต๋ ๋ ์ฝ๋ ๋ฐ์ ๊ฐ๋ฅ:
| id | name |
|------|----------|
| NULL | Alice |
| NULL | Bob |
- ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ ์๋ฐ: ํ ์ด๋ธ์ ๊ณ ์ ์ฑ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.
- ๋ ์ฝ๋ ๊ตฌ๋ถ ๋ถ๊ฐ: ํน์ ๋ ์ฝ๋๋ฅผ ์ ๋ฐ์ดํธํ๊ฑฐ๋ ์ญ์ ํ ๋ ์ด๋ค ๋ ์ฝ๋๋ฅผ ๋์์ผ๋ก ํ ์ง ํ๋จํ ์ ์์ต๋๋ค.
4. ๊ฒฐ๋ก
- @Id: JPA์์ ์ํฐํฐ์ ํ ์ด๋ธ ๊ฐ์ ๋งคํ์์ ํ์์ ์ธ ์ด๋ ธํ ์ด์ ์ผ๋ก, Primary Key๋ฅผ ๋ฐ๋์ ์ง์ ํด์ผ ํฉ๋๋ค.
- @GeneratedValue: Primary Key ๊ฐ์ ์๋์ผ๋ก ์์ฑํ์ฌ ๊ฐ๋ฐ์์ ์๋ ์ค์ ๋ถ๋ด์ ์ค์ฌ์ค๋๋ค.
- ๋ ์ด๋ ธํ ์ด์ ์์ด JPA๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ ๋ฌธ์ ์ JPA ๋์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
@PersistenceContext์ ์ญํ
1. @PersistenceContext๋?
@PersistenceContext
๋ JPA(Java Persistence API)์์ EntityManager๋ฅผ ์ฃผ์
ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ์ด๋
ธํ
์ด์
์
๋๋ค.
EntityManager๋ JPA์ ํต์ฌ ๊ฐ์ฒด๋ก, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉํ๋ฉฐ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ญํ ์ ํฉ๋๋ค.
2. ์ฃผ์ ์ญํ
- EntityManager ์ฃผ์
:
@PersistenceContext
๋ ์ปจํ ์ด๋์์ ๊ด๋ฆฌ๋๋ EntityManager๋ฅผ ํด๋น ํ๋์ ์ฃผ์ ํฉ๋๋ค. - Persistence Context ๊ด๋ฆฌ: ํธ๋์ญ์ ๋ฒ์ ๋ด์์ EntityManager๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ํ์ํ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ด๋ฆฌ๊ณ ๋ซํ๋๋ค.
- Persistence Unit ์ง์ ๊ฐ๋ฅ: ์ฌ๋ฌ Persistence Unit์ด ์์ ๊ฒฝ์ฐ,
unitName
์์ฑ์ ํตํด ํน์ Persistence Unit์ ์ ํํ ์ ์์ต๋๋ค.
3. ์ฌ์ฉ ์์
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
@PersistenceContext
private EntityManager entityManager;
public User findUserById(Long id) {
return entityManager.find(User.class, id); // User ์ํฐํฐ ์กฐํ
}
public void saveUser(User user) {
entityManager.persist(user); // User ์ํฐํฐ ์ ์ฅ
}
}
4. ์ฃผ์ ํน์ง
- ์๋ ๊ด๋ฆฌ: JPA ๊ตฌํ์ฒด(Hibernate ๋ฑ)๊ฐ EntityManager์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
- ํธ๋์ญ์ ๊ธฐ๋ฐ ๋์: EntityManager๋ ํธ๋์ญ์ ๋ฒ์์์ ์ด๋ฆฌ๊ณ ๋ซํ๋ฉฐ, ํธ๋์ญ์ ์ด ๋๋๋ฉด ์๋์ผ๋ก ์ ๋ฆฌ๋ฉ๋๋ค.
- ์คํ๋ง ์ฐ๋: ์คํ๋ง ํ๋ ์์ํฌ๋
@PersistenceContext
๋ฅผ ํตํด EntityManager๋ฅผ ์์กด์ฑ์ผ๋ก ์ฃผ์ ํฉ๋๋ค. - Persistence Unit ์ ํ ๊ฐ๋ฅ: ์ฌ๋ฌ Unit์ด ์์ ๊ฒฝ์ฐ ํน์ Unit์ ์ง์ ํ ์ ์์ต๋๋ค.
@PersistenceContext(unitName = "myPersistenceUnit") private EntityManager entityManager;
5. @Autowired์์ ์ฐจ์ด
์คํ๋ง์์ @Autowired
๋ฅผ ํตํด EntityManager๋ฅผ ์ฃผ์
ํ ์๋ ์์ง๋ง, @PersistenceContext
๋ JPA ํ์ค์ ๋ฐ๋ฅธ ๋ฐฉ์์
๋๋ค. ๋ฐ๋ผ์ ํ์ค์ ๋ฐ๋ฅด๊ณ ์ ํ ๋๋ @PersistenceContext
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ๋ช
์์ ์
๋๋ค.
6. ์ค์ ๋ฐ ๋์
Spring Boot์์๋ JPA ์ค์ ์ด ๊ฐ์ํ๋์ด ์์ผ๋ฉฐ, application.properties
์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ์ ์ถ๊ฐํ๋ฉด EntityManager๊ฐ ์๋์ผ๋ก ์์ฑ๋ฉ๋๋ค:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=update
7. ๊ฒฐ๋ก
@PersistenceContext
๋ EntityManager๋ฅผ ์ฃผ์ ๋ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉํ ์ ์๋๋ก ํฉ๋๋ค.- JPA ํ์ค ๋ฐฉ์์ผ๋ก EntityManager๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์คํ๋ง ํ๋ ์์ํฌ์ ์ฝ๊ฒ ์ฐ๋๋ฉ๋๋ค.
- ํธ๋์ญ์ ๋ฒ์ ๋ด์์ EntityManager์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
์ด ๊ธ์ด JPA๋ฅผ ์ฌ์ฉํ๋ ๋ฐ ๋์์ด ๋์๊ธธ ๋ฐ๋๋๋ค! ๐
๐ฅ ํธ๋์ญ์ ๊ณผ ์ํฐํฐ๋งค๋์ ์ ๊ด๊ณ
ํธ๋์ญ์ (Transaction)๊ณผ ์ํฐํฐ๋งค๋์ (EntityManager)๋ JPA์์ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฐํฐ ๊ฐ์ ์ํธ์์ฉ์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ํจ๊ป ๋์ํฉ๋๋ค.
1. EntityManager๋?
EntityManager๋ JPA์์ ์์์ฑ ์ปจํ ์คํธ(Persistence Context)๋ฅผ ๊ด๋ฆฌํ๋ ํต์ฌ ๊ฐ์ฒด์ ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ํธ์์ฉ ๋ฐ ์ํฐํฐ์ ์ํ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
- CRUD ์์
์ํ:
persist
,find
,merge
,remove
. - ์ํฐํฐ ์ํ ์ถ์ ๋ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐํ.
- ์์์ฑ ์ปจํ ์คํธ ๊ด๋ฆฌ.
2. Transaction์ด๋?
Transaction์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๋ ผ๋ฆฌ์ ๋จ์๋ก, ์์ ์ ์์์ฑ, ์ผ๊ด์ฑ, ๊ฒฉ๋ฆฌ์ฑ, ์ง์์ฑ์ ๋ณด์ฅํฉ๋๋ค (ACID ์์ฑ).
- ์์ ๋จ์๋ฅผ ๊ทธ๋ฃนํํ์ฌ ๋ชจ๋ ์ฑ๊ณตํ๊ฑฐ๋ ๋ชจ๋ ์คํจํ๊ฒ ๋ง๋ญ๋๋ค.
- EntityManager๋ ํธ๋์ญ์ ๋ด์์๋ง ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธ์์ฉํฉ๋๋ค.
3. EntityManager์ Transaction์ ๊ด๊ณ
EntityManager์ Transaction์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ํตํด ์ฐ๊ฒฐ๋ฉ๋๋ค. ์ฃผ์ ๊ด๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- EntityManager๋ ํธ๋์ญ์ ๋ฒ์ ๋ด์์ ๋์ํฉ๋๋ค.
- ํธ๋์ญ์ ์์ ์ ์์์ฑ ์ปจํ ์คํธ๊ฐ ํ์ฑํ๋๋ฉฐ, ์ปค๋ฐ ๋๋ ๋กค๋ฐฑ ์ ์ข ๋ฃ๋ฉ๋๋ค.
- ํธ๋์ญ์ ์์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณ๊ฒฝ ์์ ์ด ์ํ๋์ง ์์ต๋๋ค.
4. ์ฃผ์ ๋์ ์์
ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์ ํธ๋์ญ์ ๊ด๋ฆฌ
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin(); // ํธ๋์ญ์
์์
Member member = new Member();
member.setName("John Doe");
em.persist(member); // ์ํฐํฐ ์ ์ฅ
tx.commit(); // ํธ๋์ญ์
์ปค๋ฐ
} catch (Exception e) {
tx.rollback(); // ํธ๋์ญ์
๋กค๋ฐฑ
} finally {
em.close();
}
์คํ๋ง์์ @Transactional ์ฌ์ฉ
@Service
public class MemberService {
@Transactional
public void createMember(String name) {
Member member = new Member();
member.setName(name);
memberRepository.save(member);
}
}
๐ฅ ์์์ฑ ์ปจํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
์์์ฑ ์ปจํ ์คํธ(Persistence Context)๋ JPA์์ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ ์ฅ์์ ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ด์ ์ค๊ฐ ๊ณ์ธต์ผ๋ก, ์ํฐํฐ์ ์ํ๋ฅผ ์ถ์ ํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐํํฉ๋๋ค.
1. ์์์ฑ ์ปจํ ์คํธ์ ํน์ง
- 1์ฐจ ์บ์: ๋์ผํ ์ํฐํฐ๋ฅผ ์ฌ๋ฌ ๋ฒ ์กฐํํด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.
- ๋ณ๊ฒฝ ๊ฐ์ง(Dirty Checking): ์ํฐํฐ์ ์ํ ๋ณํ๋ฅผ ๊ฐ์งํ์ฌ ํธ๋์ญ์ ์ปค๋ฐ ์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํฉ๋๋ค.
- ์ง์ฐ ๋ก๋ฉ(Lazy Loading): ํ์ํ ์์ ์๋ง ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- ๋์ผ์ฑ ๋ณด์ฅ: ๋์ผํ ์์์ฑ ์ปจํ ์คํธ ๋ด์์๋ ๋์ผํ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
2. ์ํฐํฐ์ ์ํ
์ํฐํฐ๋ JPA์์ ๋ค์ ๋ค ๊ฐ์ง ์ํ ์ค ํ๋๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค:
- ๋น์์(Transient): JPA๊ฐ ๊ด๋ฆฌํ์ง ์๋ ์ํ.
- ์์(Managed): ์์์ฑ ์ปจํ ์คํธ์์ ๊ด๋ฆฌ๋๋ ์ํ.
- ์ค์์(Detached): ์์์ฑ ์ปจํ ์คํธ์์ ๋ถ๋ฆฌ๋ ์ํ.
- ์ญ์ (Removed): ์ญ์ ์ํ๋ก, ํธ๋์ญ์ ์ปค๋ฐ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ญ์ ๋จ.
3. ์ฃผ์ ๊ธฐ๋ฅ
1์ฐจ ์บ์
์ํฐํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ์ ์ต์ํํฉ๋๋ค.
Member member1 = em.find(Member.class, 1L); // DB์์ ์กฐํ
Member member2 = em.find(Member.class, 1L); // 1์ฐจ ์บ์์์ ์กฐํ (์ฟผ๋ฆฌ ๋ฐ์ X)
๋ณ๊ฒฝ ๊ฐ์ง
์ํฐํฐ ๋ณ๊ฒฝ ์ฌํญ์ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ๋ฐ์ํฉ๋๋ค.
Member member = em.find(Member.class, 1L);
member.setName("Jane Doe"); // ๋ณ๊ฒฝ ๊ฐ์ง
em.getTransaction().commit(); // UPDATE ์ฟผ๋ฆฌ ์คํ
์ฐ๊ธฐ ์ง์ฐ
๋ณ๊ฒฝ ์ฌํญ์ ํธ๋์ญ์ ์ปค๋ฐ ์์ ์ ํ๊บผ๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํฉ๋๋ค.
em.persist(member1);
em.persist(member2);
em.getTransaction().commit(); // INSERT ์ฟผ๋ฆฌ ์คํ
4. ๊ฒฐ๋ก
- ์์์ฑ ์ปจํ ์คํธ๋ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ํธ์์ฉ์ ์ต์ ํํฉ๋๋ค.
- ํธ๋์ญ์ ๊ณผ ๊ฒฐํฉํ์ฌ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
ํธ๋์ญ์ ๊ณผ ์์์ฑ ์ปจํ ์คํธ: ๊ฐ์ ID๋ ๊ฐ์ ์ํฐํฐ๋ก ์๋ณ
1. ํธ๋์ญ์ ๊ณผ ์์์ฑ ์ปจํ ์คํธ
ํธ๋์ญ์ ๊ณผ ์์์ฑ ์ปจํ ์คํธ๋ JPA์ ํต์ฌ ๊ฐ๋ ์ผ๋ก, ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ณ ์ํฐํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด ํจ๊ป ๋์ํฉ๋๋ค.
1.1 ํธ๋์ญ์
- ํธ๋์ญ์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ๋ ผ๋ฆฌ์ ๋จ์์ ๋๋ค.
- ํธ๋์ญ์ ์ด ์์๋๋ฉด JPA๋ ํด๋น ํธ๋์ญ์ ๋ด์์ ํ๋์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ ํตํด ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
1.2 ์์์ฑ ์ปจํ ์คํธ
- ์์์ฑ ์ปจํ ์คํธ๋ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ(์บ์)์ผ๋ก, ์ํฐํฐ์ ์ํ๋ฅผ ์ถ์ ํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐํ๋ฅผ ์ํํฉ๋๋ค.
- ๋์ผํ ํธ๋์ญ์ ๋ด์์ ๋์ผํ ์์์ฑ ์ปจํ ์คํธ๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
2. ์ฝ๋์์ ์ผ์ด๋๋ ์ฃผ์ ์์
@Test
@Transactional
@Rollback(false)
public void testMember() throws Exception {
// given
Member member = new Member();
member.setUsername("memberA");
// when
Long saveId = memberRepository.save(member);
Member findMember = memberRepository.find(saveId);
// then
Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
Assertions.assertThat(findMember).isEqualTo(member);
}
2.1 ์ฃผ์ ์์
- @Transactional: ํ ์คํธ ๋ฉ์๋์์ ํธ๋์ญ์ ์ด ์์๋๊ณ , JPA๋ ํ๋์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์์ฑํฉ๋๋ค.
- save:
memberRepository.save(member)
๋ฅผ ํธ์ถํ๋ฉด, ์ํฐํฐ๊ฐ ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋ฉ๋๋ค. - find:
memberRepository.find(saveId)
๋ฅผ ํธ์ถํ๋ฉด JPA๋ ๋จผ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ํ์ธํฉ๋๋ค. - Assertions:
findMember
์member
๊ฐ ๊ฐ์ ์ธ์คํด์ค์์ ๊ฒ์ฆํฉ๋๋ค.
3. ์์์ฑ ์ปจํ ์คํธ์ ๋์
3.1 ์ํฐํฐ ์ ์ฅ (persist)
memberRepository.save(member)
ํธ์ถ ์:
member
๊ฐ์ฒด๊ฐ ์์์ฑ ์ปจํ ์คํธ์ ์ ์ฅ๋ฉ๋๋ค.- ํธ๋์ญ์ ์ด ์ปค๋ฐ๋ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ฉ๋๋ค.
3.2 ์ํฐํฐ ์กฐํ (find)
memberRepository.find(saveId)
ํธ์ถ ์:
- JPA๋ ๋จผ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ํ์ธํฉ๋๋ค.
- ๋์ผํ ID์ ์ํฐํฐ๊ฐ ์ด๋ฏธ ์์์ฑ ์ปจํ ์คํธ์ ์กด์ฌํ๋ฉด, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ ์์ด ์บ์๋ ์ํฐํฐ๋ฅผ ๋ฐํํฉ๋๋ค.
4. ์ค์ํ ๊ฐ๋ : "๊ฐ์ ์์์ฑ ์ปจํ ์คํธ์์ ๊ฐ์ ID๋ ๊ฐ์ ์ํฐํฐ"
- ๊ฐ์ ํธ๋์ญ์ ๋ด์์ ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ ์ฌ์ฉ: ํธ๋์ญ์ ์ด ์ ์ง๋๋ฉฐ, ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- ์์์ฑ ์ปจํ ์คํธ์ ๋์ผ์ฑ ๋ณด์ฅ: ๋์ผํ ID ๊ฐ์ ๊ฐ์ง ์ํฐํฐ๋ ๊ฐ์ ๊ฐ์ฒด๋ก ๊ด๋ฆฌ๋ฉ๋๋ค.
- ์บ์ฑ ํจ๊ณผ: ๋์ผํ ์ํฐํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ๋ฌ ๋ฒ ์กฐํํ์ง ์์ต๋๋ค.
5. Assertions์ ๋ํ ์ค๋ช
Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
Assertions.assertThat(findMember).isEqualTo(member);
์ Assertions๋ ๋ค์์ ๊ฒ์ฆํฉ๋๋ค:
- ID์ Username ๋น๊ต:
findMember
์member
์ ID์ Username์ด ๋์ผํฉ๋๋ค. - ๊ฐ์ฒด ๋์ผ์ฑ ๋น๊ต:
findMember
์member
๊ฐ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
6. ์์ ์ ํต์ฌ ์์ฝ
- ์์์ฑ ์ปจํ ์คํธ๋ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์บ์ ์ญํ ์ ํฉ๋๋ค.
- 1์ฐจ ์บ์: ๋์ผํ ID์ ์ํฐํฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์กฐํํ์ง ์๊ณ ์บ์์์ ๋ฐํ๋ฉ๋๋ค.
- ํธ๋์ญ์ ๊ณผ ๊ฒฐํฉ: ๊ฐ์ ํธ๋์ญ์ ๋ด์์๋ ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ID๋ก ๊ฐ์ ์ํฐํฐ ์๋ณ: ๊ฐ์ ์์์ฑ ์ปจํ ์คํธ ๋ด์์ ๋์ผํ ID๋ฅผ ๊ฐ์ง ์ํฐํฐ๋ ๊ฐ์ ๊ฐ์ฒด๋ก ์ทจ๊ธ๋ฉ๋๋ค.
7. ๋น์ ๋ก ์ดํดํ๊ธฐ
- ์์์ฑ ์ปจํ ์คํธ๋ ์ฌ๋ฌด์ค ์บ๋น๋: ํ ๋ฒ ์ ์ฅ๋ ๋ฌธ์๋ ๋์ผํ ํธ๋์ญ์ ๋์ ์บ๋น๋์์ ์ฐพ์ ์ฌ์ฉํฉ๋๋ค.
- ๊ฐ์ ๋ฌธ์๋ผ๋ฉด ๊ฐ์ ๋ด์ฉ: ID(๋ฌธ์ ๋ฒํธ)๊ฐ ๊ฐ์ผ๋ฉด ํญ์ ๊ฐ์ ๋ฌธ์๋ฅผ ๋ฐํํฉ๋๋ค.
JPA์์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ ์ค์
JPA์์ ์ํฐํฐ ๊ฐ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ค์ ํ๋ ๊ฒ์ ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ๋ ์ธก์ ๋ช ํํ ํ๊ธฐ ์ํด ์ค์ํฉ๋๋ค. ์๋์ ๊ทธ ์ด์ ๋ฅผ ์ค๋ช ํฉ๋๋ค.
1. ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ญํ
JPA์์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ธ๋ ํค(Foreign Key, FK)๋ฅผ ๊ด๋ฆฌํ๋ ์ํฐํฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์ฃผ์ธ์ ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ์ํ ์ฑ ์์ด ์์ต๋๋ค.
- ์ฃผ์ธ์
@JoinColumn
์ ํตํด ์ธ๋ ํค๋ฅผ ๋งคํํฉ๋๋ค. - ์ฃผ์ธ์ด ์๋ ์ชฝ(๋น์ฃผ์ธ)์ ๋จ์ํ ๋งคํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ์ญํ ๋ก, ์ธ๋ ํค๋ฅผ ์ง์ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, Order
์ Member
๊ฐ @OneToMany
์ @ManyToOne
๊ด๊ณ๋ก ์ฐ๊ฒฐ๋์ด ์๋ค๋ฉด:
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋
Order
ํ ์ด๋ธ์ ์ธ๋ ํค๊ฐ ์กด์ฌํฉ๋๋ค. - JPA์์๋
Order
์ํฐํฐ๊ฐ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ์ค์ ๋์ด์ผ ์ธ๋ ํค๋ฅผ ์กฐ์ํ ์ ์์ต๋๋ค.
2. ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ์ ์ธ๋ ํค
๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์์๋ ์ธ๋ ํค๊ฐ ํ์ชฝ ํ ์ด๋ธ์๋ง ์กด์ฌํ์ง๋ง, JPA ์ํฐํฐ๋ ๊ฐ์ฒด์งํฅ์ ๋ชจ๋ธ๋ง์ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ ์์ชฝ ์ํฐํฐ๊ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
@Entity
public class Member {
@OneToMany(mappedBy = "member") // ๋น์ฃผ์ธ
private List<Order> orders;
}
@Entity
public class Order {
@ManyToOne
@JoinColumn(name = "member_id") // ์ฃผ์ธ
private Member member;
}
Order
์ํฐํฐ๋ ์ธ๋ ํคmember_id
๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ฏ๋ก ์ฃผ์ธ์ด ๋ฉ๋๋ค.Member
์ํฐํฐ๋mappedBy
์์ฑ์ ํตํดOrder
์member
ํ๋์ ์ํด ๋งคํ๋๋ค๋ ๊ฒ์ ๋ํ๋ด๋ฉฐ, ๋น์ฃผ์ธ์ผ๋ก ์ค์ ๋ฉ๋๋ค.
3. ์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ ์๋ชป ์ค์ ํ์ ๊ฒฝ์ฐ ๋ฌธ์
์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ ์๋ชป ์ค์ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค:
- ๋ณ๊ฒฝ ์ฌํญ ๋ฏธ๋ฐ์: ๋น์ฃผ์ธ ์ชฝ ์ํฐํฐ์ ๊ฐ์ ์ค์ ํด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์๋์ง ์์ต๋๋ค.
Member member = em.find(Member.class, 1L);
Order order = new Order();
member.getOrders().add(order); // ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ์ ์ ๋จ
์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ:
Order order = new Order();
order.setMember(member); // ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์๋จ
- ์์์น ๋ชปํ ๊ฒฐ๊ณผ: ๊ฐ์ฒด ๊ฐ ์ฐธ์กฐ ์ํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ๊ฐ ๋ถ์ผ์นํ ์ ์์ต๋๋ค.
Member member = em.find(Member.class, 1L);
Order order = new Order();
order.setMember(member); // ์ฃผ์ธ์ ์ค์
member.getOrders().add(order); // ๋น์ฃผ์ธ๋ ๋๊ธฐํ
4. ์ JPA๋ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ๊ฐ์ ํ ๊น?
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ธ๋ ํค๋ฅผ ํ์ชฝ ํ ์ด๋ธ์๋ง ๋๊ธฐ ๋๋ฌธ์, ์ด๋ฅผ ๋งคํํ๋ JPA๋ ๋ง์ฐฌ๊ฐ์ง๋ก ํ์ชฝ๋ง ์ฑ ์์ ๊ฐ๋๋ก ๊ฐ์ ํฉ๋๋ค.
์๋ฐฉํฅ ๊ด๊ณ๋ฅผ ํ์ฉํ๋ฉด์๋ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ์ ์งํ๋ ค๋ฉด ํ์ชฝ์์๋ง ์ธ๋ ํค๋ฅผ ๋ณ๊ฒฝํ๋๋ก ์ค๊ณํด์ผ ํผ๋์ ์ค์ผ ์ ์์ต๋๋ค.
5. ๊ฒฐ๋ก
์ํฐํฐ ๊ฐ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ๋ช ํํ ์ค์ ํ๋ ๊ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ์ ๊ฐ์ฒด ์ํ์ ์ผ์น๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด ํ์์ ์ ๋๋ค. ์ฃผ์ธ์ ์ค์ ํ์ง ์๊ฑฐ๋ ์๋ชป ์ค์ ํ๋ฉด ๋ฐ์ดํฐ๊ฐ ๋ฐ์๋์ง ์๊ฑฐ๋ ์ผ๊ด์ฑ์ด ๊นจ์ง ์ ์์ต๋๋ค. ๋ฐ๋ผ์ JPA์์๋ ํญ์ ์ธ๋ ํค๋ฅผ ์ง์ ๊ด๋ฆฌํ ์ํฐํฐ๋ฅผ ์ฃผ์ธ์ผ๋ก ์ง์ ํด์ผ ํฉ๋๋ค.
๐ ์ฐธ๊ณ
์ํฐํฐ ๋งค๋์ ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ ํํ๊ฒ ์ดํดํด๋ณด์
JPA ๊ณต์ ๋ฌธ์์ Hibernate ๋ฌธ์๋ฅผ ๋ณด๊ณ ์ํฐํฐ ๋งค๋์ ์ ์์์ฑ ์ปจํ ์คํธ๋ฅผ ์ ํํ๊ฒ ์ดํดํ์.
psvm.kr
๋๊ธ