Map 형태의 캐시 저장소
동일성(Identity) 보장
같은 트랜잭션 안에서 같은 ID로 조회한 엔티티는 항상 동일한 메모리 주소의 인스턴스임이 보장
(==비교 시true보장)
UPDATE SQL을 생성하여 DB에 반영@Transactional
public void updateMemberName(Long id, String newName) {
Member member = memberRepository.findById(id).orElseThrow(
() -> new IllegalStateExcetion("존재하지 않는 유저 입니다.")
); // 영속성 컨텍스트가 관리 시작
// member.updateName()만 호출했을 뿐이고, update 쿼리는 없는 상황!
member.updateName(newName);
} // 👈🏻 트랜잭션이 끝나는 이 시점에 JPA가 변경을 감지하고 UPDATE 쿼리를 날려준다.
memberRepository.save()를 호출INSERT 등)을 모아둠
persist), 수정, 삭제(remove), 조회(find)JpaRepository(Spring Data JPA)
public interface MemberRepository extends JpaRepository<Member, Long> {
}
EntityManager
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
public Member save(Member member) {
if (member.getId() == null) {
em.persist(member);
return member;
} else {
return em.merge(member);
}
}
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
public boolean existsById(Long id) {
Long count = em.createQuery(
"select count(m) from Member m where m.id = :id", Long.class)
.setParameter("id", id)
.getSingleResult();
return count > 0;
}
public void deleteById(Long id) {
Member member = em.find(Member.class, id);
if (member != null) {
em.remove(member);
}
}
}
Spring Data JPA는 JPA의 핵심인 Entity Manager를 편리하게 사용할 수 있도록 추상화한 것!
@Transactional어노테이션이 달린 메서드를 실행하고 있는데, 그 메서드 안에서@Transactional어노테이션이 달린 또다른 메서드를 실행하면 어떻게 될까?
propagation 옵션
REQUIRED (기본값)
REQUIRES_NEW
NESTED
SUPPORTS
NOT_SUPPORTED
MANDATORY
IllegalTransactionStateException 던짐NEVER
IllegalTransactionStateException 던짐일단 이런 게 있구나 정도로 넘어가자. 실제 쓰이는 것은
REQUIRED가 99.9%이다.
트랜잭션들이 어느 정도까지 격리되어 실행될 것인가?
일관성과 동시 처리 성능 중 뭐가 더 중요한가?
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
INSERT하거나 기존 레코드를 DELETE함으로써 쿼리의 결과 집합 행 개수가 달라질 수 있다SELECT ... FOR UPDATE: 쓰기 잠금을 걸고 조회, UPDATE 시도 등)SERIALIZABLE