일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 1차원 DP
- 2차원 dp
- 99클럽
- @BeforeAll
- @BeforeEach
- @Builder
- @Entity
- @GeneratedValue
- @GenericGenerator
- @NoargsConstructor
- @Query
- @Table
- @Transactional
- Actions
- Amazon EFS
- amazon fsx
- Android Studio
- ANSI SQL
- ApplicationEvent
- assertThat
- async/await
- AVG
- AWS
- Azure
- bind
- builder
- button
- c++
- c++ builder
- c03
- Today
- Total
기록
[자바 ORM 표준 JPA 프로그래밍] JPA 트랜잭션 관리와 캐싱(16장) 본문
시작하면서
Java Persistence API(JPA)는 객체와 관계형 데이터베이스 간의 매핑을 지원하는 강력한 도구로, 개발자들이 SQL을 직접 다루지 않고도 데이터를 효율적으로 관리할 수 있도록 돕습니다. 이 글에서는 책 "자바 ORM 표준 JPA 프로그래밍"의 16장에서 다룬 중요한 개념과 예제를 중심으로 내용을 정리하였습니다.
1. 격리 수준과 문제점
JPA에서는 트랜잭션 격리 수준을 이해하고 데이터 일관성을 유지하는 것이 중요합니다. 격리 수준에 따라 발생할 수 있는 문제점을 아래 표에 정리하였습니다.
격리 수준 | 설명 | 발생할 수 있는 문제 |
---|---|---|
READ UNCOMMITTED | 트랜잭션에서 커밋되지 않은 데이터를 읽을 수 있음 | Dirty Read |
READ COMMITTED | 커밋된 데이터만 읽을 수 있음 | Non-repeatable Read |
REPEATABLE READ | 동일 트랜잭션 내에서 동일 데이터를 반복 조회해도 동일한 결과를 보장 | Phantom Read |
SERIALIZABLE | 가장 높은 격리 수준으로, 트랜잭션 간 완벽한 격리를 보장 | 성능 저하 |
Dirty Read란?
- Dirty Read는 한 트랜잭션에서 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있는 상황을 말합니다.
- 예를 들어, 트랜잭션 A에서 데이터 값을 수정하고 커밋하지 않았는데, 트랜잭션 B가 이를 읽는 경우입니다. 이후 트랜잭션 A가 롤백된다면, 트랜잭션 B는 유효하지 않은 데이터를 사용하게 됩니다.
Non-repeatable Read란?
- Non-repeatable Read는 한 트랜잭션 내에서 동일한 데이터를 두 번 조회할 때, 그 값이 변경되는 문제를 의미합니다.
- 예를 들어, 트랜잭션 A가 데이터를 조회한 후, 트랜잭션 B가 해당 데이터를 수정 및 커밋하고, 다시 트랜잭션 A가 조회했을 때 값이 달라지는 상황입니다.
Phantom Read란?
- Phantom Read는 한 트랜잭션 내에서 동일한 조건으로 데이터를 조회했을 때, 중간에 다른 트랜잭션이 데이터를 삽입하거나 삭제하여 결과가 달라지는 문제를 말합니다.
- 예를 들어, 트랜잭션 A가 특정 조건의 데이터를 조회한 후, 트랜잭션 B가 새로운 데이터를 삽입하고 커밋하면, 다시 트랜잭션 A가 조회했을 때 결과가 달라질 수 있습니다.
2. 트랜잭션과 락
트랜잭션 관리에서 데이터의 정합성과 동시성을 보장하기 위해 락(Lock)을 활용합니다. 락은 데이터베이스에서 공유 자원을 보호하기 위한 메커니즘으로, JPA에서는 낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)을 지원합니다.
3. 낙관적 락과 비관적 락
낙관적 락 (Optimistic Lock):
- 데이터 충돌이 드물다고 가정하고 사용하며, 데이터 충돌 시 예외를 발생시켜 처리합니다.
@Version
필드를 사용하여 엔티티 변경 시점에 버전을 검사합니다.
비관적 락 (Pessimistic Lock):
- 데이터 충돌이 빈번하다고 가정하고, 데이터에 락을 걸어 다른 트랜잭션의 접근을 차단합니다.
- 데이터베이스의 락 메커니즘을 직접 활용하며,
EntityManager
의lock()
메서드로 구현됩니다.
4. 낙관적 락의 구현 방법
낙관적 락은 엔티티 클래스에 @Version
어노테이션을 사용하여 구현합니다. 이는 데이터 변경 시마다 버전 필드를 자동으로 증가시켜 충돌 여부를 판단합니다.
예제 코드:
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
@Version
private int version;
private String name;
}
Product product = em.find(Product.class, productId);
product.setName("Updated Name");
// 트랜잭션 커밋 시 JPA는 버전 값을 확인하여 충돌 여부를 판단합니다.
5. 비관적 락의 구현 방법
비관적 락은 EntityManager
의 lock()
메서드를 사용하여 구현합니다. 주로 LockModeType.PESSIMISTIC_WRITE
또는 LockModeType.PESSIMISTIC_READ
를 사용합니다.
예제 코드:
Product product = em.find(Product.class, productId, LockModeType.PESSIMISTIC_WRITE);
product.setName("Updated Name");
// 이 동안 다른 트랜잭션은 해당 엔티티를 수정할 수 없습니다.
6. 2차 캐시: 애플리케이션 조회 성능 최적화
JPA의 2차 캐시는 애플리케이션 전체에서 데이터를 공유하여 조회 성능을 최적화합니다. 2차 캐시는 주로 자주 변경되지 않는 데이터를 캐싱하여 데이터베이스 접근 빈도를 줄이는 데 사용됩니다.
2차 캐시의 개념:
- 데이터베이스와 애플리케이션 사이에서 데이터를 캐싱합니다.
@Cacheable
어노테이션으로 특정 엔티티를 캐싱 대상으로 지정할 수 있습니다.
1차 캐시와 2차 캐시의 차이점:
- 1차 캐시:
- 영속성 컨텍스트 내에서 관리되며, 동일한 트랜잭션 범위 내에서만 유효합니다.
- 동일한 트랜잭션에서 조회 시, 데이터베이스 접근 없이 캐시에서 데이터를 반환합니다.
- 2차 캐시:
- 애플리케이션 전체에서 공유되며, 여러 트랜잭션 간에 데이터를 재사용할 수 있습니다.
- 자주 조회되지만 변경이 드문 데이터를 캐싱하여 데이터베이스 부하를 줄이는 데 유리합니다.
2차 캐시의 적용 방법:
- JPA 제공 프로바이더(Hibernate 등)의 2차 캐시를 활성화합니다.
persistence.xml
설정 파일에서 캐시 관련 설정을 추가합니다.- 엔티티 클래스에
@Cacheable
어노테이션을 적용합니다.
예제 코드:
@Entity
@Cacheable
public class Category {
@Id @GeneratedValue
private Long id;
private String name;
}
persistence.xml
설정:
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
7. 2차 캐시와 스프링의 캐시 제공 기능
2차 캐시는 다양한 캐시 프로바이더와 함께 동작할 수 있으며, 스프링 프레임워크에서 제공하는 캐시와 유사하게 동작합니다. 참고로, 스프링 공식 문서에 따르면, 다음과 같은 캐시 프로바이더를 지원합니다:
- JCache (JSR-107): EhCache 3, Hazelcast, Infinispan 등
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Cache2k
- Simple (기본 제공)
스프링에서 Redis와 같은 캐시를 활용할 경우, 위의 프로바이더 중 하나를 선택하여 효율적인 캐싱 구조를 구성할 수 있습니다. 공식 문서를 참고하여 설정 방법과 지원되는 세부 사항을 확인할 수 있습니다: Spring Boot Caching Documentation
결론
JPA는 데이터베이스와의 상호작용을 단순화하고, 객체 지향적인 데이터 관리를 가능하게 합니다. 하지만 트랜잭션 관리, 로딩 전략, 캐시 활용, 락 메커니즘, 그리고 격리 수준 등의 다양한 설정 요소를 적절히 이해하고 사용해야 성능과 일관성을 모두 확보할 수 있습니다.
'교육 > 책' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 예외 처리, 엔티티 비교, 프록시 문제 및 성능 최적화(15장) (0) | 2024.12.14 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] JPA 컬렉션과 부가 기능: 컬렉션, 컨버터, 리스너, 엔티티 그래프(14장) (0) | 2024.12.14 |
[자바 ORM 표준 JPA 프로그래밍] 일반적인 트랜잭션 관리와 뷰에서 필요한 데이터에 접근(13장) (0) | 2024.12.07 |
[자바 ORM 표준 JPA 프로그래밍] 스프링 데이터 JPA/성능 최적화 (12장-2) (0) | 2024.12.07 |
[자바 ORM 표준 JPA 프로그래밍] 스프링 데이터 JPA 기능/쿼리 메서드, 페이징과 정렬, 벌크 연산 (12장-1) (0) | 2024.12.07 |