728x90

개요

개발을 하거나 면접을 보게 되면 Spring Data Jpa관련 단골 질문으로 가장 많이 나오는 내용이라 생각합니다.

 

그럼 도대체 OSIV가 뭐길래 JPA에서 계속 말이 나오게 되는 걸까? 한번 알아보도록 하겠습니다.


OSIV란

OSIV란 Open Session In View의 약자로써 사실 JPA가 도입되면서 Open EntityManager In View로 개념이 확립되었으나 편의상 지금까지 OSIV라고 부르고 있습니다.

말 그대로 OSIV는 View까지 EntityManager를 열어두는 것을 의미합니다.

 

그럼 JPA에서 EntityManager이라 함은 무엇일까요?

바로 영속성 컨텍스트를 의미합니다.

 

영속성 컨텍스트는 요청이 들어오면 생성되고 사라지는 휘발성 콘텍스트입니다.

해당 콘텍스트는 기본적으로 요청이 들어오면 생성되고, 요청이 끝나면 사라지게끔 되어있는데, 이는 OSIV 설정이 기본으로 True로 설정되어 있어 가능한 일입니다.

 

만약 OSIV가 False로 설정되어 있다면 영속성 콘텍스트는 Transaction범위에 따라 생성되고 Transaction이 끝날 시 사라지게 됩니다.

 

이로써 OSIV가 어떤 설정인지 알았으니 해당 설정이 기능과 성능에 미치는 영향에 대해 알아보겠습니다.


OSIV가 미치는 영향

OSIV 설정은 아래 그림으로 한 번에 확인할 수 있습니다.

위와 같이 데이터를 생성, 수정, 삭제 기능들은 트랜잭션 범위 내에서 작업이 가능합니다.

다만 읽기 기능의 경우 영속성 콘텍스트 범위 내에 있을 경우 읽기가 가능한데,

OSIV는 영속성 콘텍스트를 view까지 늘려 트랜잭션이 아닌 요청의 생존 범위까지 늘리는 것을 의미합니다.

 

즉 생성, 수정, 삭제는 OSIV의 목적은 아니고, 읽기 범위를 늘리는 것이 주목적이라고 보시면 됩니다.

 

그럼 왜! 읽기 범위를 늘리는 것인가?

이는 Lazy Loading과 밀접한 관련이 있습니다.

 

Lazy Loading이란 지연 읽기 기능인데, 처음 데이터베이스에서 조회하는 것이 아닌 추후 해당 데이터를 사용할 때 조회하는 기능입니다.

 

해당 기능을 사용할 때, 영속성 콘텍스트의 생존범위 내에서 로딩하는지가 중요한데 이를 어디까지 허용할 것인지를 조절할 수 있다고 보시면 좋을 것 같습니다.

 

그럼 해당 기능이 왜 성능 향상에 기여할 수 있는가? 영속성 콘텍스트를 유지하는 것 또한 많은 자원을 소모하게 됩니다.

이를 View까지 유지하지 않고 트랜잭션 범위에 맞춰 종료하게 되면 OSIV가 TRUE인 상태보다 좀 더 효율적으로 자원을 사용할 수 있게 됩니다.

 

해당 옵션은 위에서 말했듯 default True인 옵션입니다.

만약 애플리케이션 성능 향상에 있어 관심이 많다면 테스트해보시길 바랍니다.


Reference

https://docs.spring.io/spring-boot/reference/data/sql.html#data.sql.jpa-and-spring-data.open-entity-manager-in-view

 

SQL Databases :: Spring Boot

Spring’s JdbcTemplate and NamedParameterJdbcTemplate classes are auto-configured, and you can autowire them directly into your own beans, as shown in the following example: import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.ste

docs.spring.io

 

 

728x90
728x90

JPA를 사용하여 데이터베이스에 락을 거는 방법은 2가지방법을 뽑아 볼 수 있습니다.

 

테이블에 행하는 행위 ( 조회, 수정, 등록, 삭제 )를 막는 비관적 락과 데이터에 버전을 명시하고 해당 버전을 통해 데이터의 일관성을 보장하는 낙관적 락이 이 경우입니다.

 

비관적 락  - Pessimistic Lock

비관적락은 데이터를 조회하고 특정 작업을 할 때 테이블에 어떤 작업도 일어나면 안되는 상황에서 사용하기 적합하다고 볼 수 있습니다.

이는 데이터의 정확성과 일관성을 보장하는 방법이며, 이 방법은 테이블에 락을 거는 행위로 성능에 큰 영향을 끼칠 수 있습니다.

 

데이터베이스의 종류에 따라 락을 걸었으나 데이터가 조회되는 경우도 있으니 이는 어떤 데이터베이스를 사용하는지를 확인을 하고 잘 선택하기 바랍니다.

public interface LectureJpaRepository extends JpaRepository<LectureEntity, Long> {
    //
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("select l from LectureEntity l where l.id = :id")
    Optional<LectureEntity> findByIdForUpdate(long id);
}

사용법은 위와 같이 조회할 때 @Lock 어노테이션을 통해 Lock을 시작하는 Start point를 설정해줍니다.

 

LockkModeType에는 아래와 같은 옵션들을 선택하여 적용할 수 있습니다.

LockModeType Action
READ Entity의 버전을 확인합니다. - jpa1.0 버전 호환
WRITE Entity가 변경이 되지 않더라도 버전을 자동으로 올려줍니다. - jpa1.0 버전 호환
OPTIMISTIC thread가 종료될 때 Entity의 버전을 확인합니다.
OPTIMISTIC_FORCE_INCREMENT Entity가 변경이 되지 않더라도 버전을 자동으로 올려줍니다.
PESSIMISTIC_READ 데이터베이스가 지원하면 비관적락을, 지원하지 않다면 명시적 락으로 통해 읽기는 가능하지만 CUD는 할 수 없어집니다.
PESSIMISTIC_WRITE 해당 쓰레드를 제외 나머지 모든 쓰레드는 lock이 해제될때까지 Block됩니다.
PESSIMISTIC_FORCE_INCREMENT 비관적으로 잠기고, Entity가 변경되지 않더라도 버전이 자동으로 오릅니다.
NONE 잠금을 걸지 않습니다.

 

public class LectureService {

    @Transactional
    public Lecture loadLecture(long lectureId) {
		// 조회 -  Lock시작
        // 작업들
        //종료 - Transaction이 종료될 때 Lock을 풉니다
    }

}

 

비관적 락의 경우 Transaction내에서 유지되며, 해당 영역 내에서 작업을 끝내야 데이터의 일관성을 유지할 수 있습니다.

너무 많은 처리 및 Transaction전파에 의해 Lock이 길어질 수 있어 주의가 필요합니다.

낙관적 락  - Optimistic Lock

Version데이터를 통해 데이터의 일관성을 보장하는 방법입니다.

 

비관적락과 달리 테이블을 잠그거나 하지는 않지만, 버전이 다를 경우 데이터 수정작업 등을 처리하지 않는 것으로 동시성을 처리하였습니다.

 

비관적락에 비해 사용하기 쉽다는 장점이 있으며, 테이블을 잠그지 않기 때문에 성능적인 측면에서 더욱 효율적으로 관리할 수 있는 방법입니다.

단점으로는 버전을 통해 데이터의 일관성을 유지하기 때문에 동시에 여러번의 요청이 들어올 경우 많은 데드락이 발생 할 수 있습니다.

 

아래와 같은 방법으로 Entity에  @Version어노테이션을 사용함으로써 간단하게 명시 할 수 있습니다.

@Entity
public class LectureEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Version
    private int version
}

 

버전의 타입으로는 int, Long, TimeStemp와 같은 자료를 사용할 수 있으며,  TimeStemp의 경우 데이터의 일관성을 보장하기에는 int와 Long타입에 비해 부적절하지만, 상황에 따라 사용하는 경우가 존재한다고 합니다.


데이터베이스에서 락을 거는 만큼 무분별한 락사용과 제대로 된 설계가 아닐 경우 큰 성능적인 이슈를 야기할 수 있습니다.

 

이를 염두하고 적절한 락을 사용하는 것을 권장합니다.

또한 이 블로그글은 Hibernate구현체, Mysql기준으로 작성된 만큼 다른 데이터베이스, 또한 다른 기능들과 같이 사용할 경우 위에 소개한 상황과 다른 상황들이 발생할 수 있으니 확인해보시기 바랍니다.

 

Hibernate공식문서: https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#locking

728x90

'Java' 카테고리의 다른 글

[ThreadLocal] Thread영역에 데이터를 저장하고 싶어요  (1) 2025.01.27
오차 없는 실수 연산 어떻게 해야 할까?  (0) 2025.01.10
[Java] Static  (3) 2024.12.26
[ Basic ] I/O Stream이란?  (0) 2024.12.23
JPA는 어떤 기술일까?  (0) 2024.04.12
728x90

JPA에 대하여

 

우리가 JPA를 알기 위해서는 사전 지식으로 ORM이 무엇인지를 알아야 합니다.

이에 이 글은 ORM부터 알아본 후 JPA에 대해 다뤄보도록 하겠습니다.

ORM이란?

ORM( Object Ralational Mapping )은 단어를 풀어 해석하면 '객체 관계형 연결'이 됩니다.

이 기술은 애플리케이션과 데이터베이스 연결 시 기존에는 SQL언어를 애플리케이션 서버에서 직접 작성하였지만, 이를 서버에서는 객체로 정의하여 행위에 대한 Action을 하면  정의된 객체를 해석하여 행위에 필요한 SQL문을 작성하여 데이터베이스로 전달하는 말 그대로의 Mapping역할을 합니다.

 

이러한 ORM은 기존 Mybatis와 같은 기술을 사용하던 것을 '객체 지향'적으로 사용하기 위해 나온 기술이라고 봐도 무방 할 것이라 생각하는데, 어떤 탄생 배경이 있는지 알아보도록 하겠습니다.

ORM 탄생 배경

우리가 개발할 때 객체 지향 언어를 사용하여 개발을 하고, 관계형 데이터베이스를 사용하게 되면 프로그램 내에서 데이터베이스와 연결하여 SQL문을 직접 작성을 해줘 데이터를 얻거나 작업을 할 수 있습니다.

 

이때 우리는 객체 지향 언어의 데이터 표현 방법관계형 데이터베이스의 데이터 표현 방법의 차이를 확인해 볼 필요가 있습니다.

 

객체 지향 언어은 데이터를 객체에 상호 연결된 그래프로 표현을 하고, 관계형 데이터베이스는 데이터를 표형식으로 표현을 하게 됩니다.

이렇게 표현 방식이 다른 두 개념을 한 프로그램에서 사용을 하려면 표형식 표현방법을 객체에 상호 연결된 그래프 방식으로 변경하는 작업을 하게 되는데, 이는 개발자에게 번거로움과 오류 발생의 원인을 제공하게 됩니다.

 

이리하여 관계형 데이터베이스와 연결하여 SQL문을 작성하는 부분을 추상화시켜버리게 되는데 이것이 ORM입니다.

ORM의 장단점

위 설명만 보면 ORM을 만능으로 볼 수도 있습니다.

개발자의 번거로움을 줄여주고!! 오류 발생의 원인을 없애 주다니!! 하고 말입니다.

하지만 대부분의 기술이 그렇듯 장단점이 존재합니다.

장점

  • 사용하기 편하다.  - 강점 -
  • 직접적인 SQL문 작성이 없는 만큼 신경써야하는 부분이 줄어든다.
  • 객체를 정의하여 사용하고 얼마든지 수정 및 확장이 쉬워 유지보수가 편하다.

단점

  • ORM만 사용하여서는 복잡한 작업( 조회 혹은 수정 등 )을 대응하기 힘들다.
  • 객체 지향적이라 객체로 관리하게 되었다고 설계를 신경써서 하지 않으면 어떤 프로그램보다 복잡하고 힘든 프로그램이 만들어진다.

데이터 베이스를 객체 지향적으로 접근할 수 있는 만큼 설계의 중요성은 이루 말할 수 없을 정도이며,

사용하다 보면 그냥 SQL사용해서 개발하고 싶다라는 생각이 들 수도 있습니다.

다만 적절히 비즈니스 로직을 나눠 분석하여 사용할 경우보다 쉽게 개발할 수 있는 기술인 것에는 틀림없다 생각합니다.


JPA이란?

JPA(Java Persistent API)는 말그대로 JAVA Application에서 '객체와 관계형 데이터베이스 간의 매핑을 위한 API' 인터페이스의 모음입니다.

이 모음에는 3가지 구현체가 존재하는데, Hibernate, EclipseLink, DataNucleus가 있습니다.

Hibernate

하이버네이트는 JDBC API를 사용하는 JPA인터페이스 구현체입니다.

이는 무슨 뜻이냐 우리가 객체로 데이터를 CRUD 하게 되면 JPA 즉 하이버네이트 내부에서는 해당 객체를 분석하여 데이터베이스로 SQL문을 보내주게 되는데 이때 사용하는 API가 JDBC API라는 것입니다.

EclipseLink

EclipseLink는 JPA인터페이스 구현체입니다.

또한 JAXB, SDO를 구현한 포괄적인 오픈소스 프레임워크로, 다양한 기능과 확장성을 강력하게 제공하고 있습니다.

DataNucleus

DataNucleus는 JPA 인터페이스 구현체입니다.

EclipseLink와 마찬가지로 다른 데이터베이스들 또한 지원하고 있습니다.

Hibernate를 왜 많이 사용하는가

글을 작성하면서 의문이 들었던 점이 왜 Hibernate는 많이 사용하거나 본 거 같은데, EclipseLink와 DataNucleus는 다루는 글을 많이 못 본 것 같다는 생각을 하였습니다. 그리고 설명들을 보면 Hibernate는 JPA 인터페이스를 구현한 가장 대표적인 오픈소스라고 하는데 EclipseLink와 DataNucleus 또한 강력한 기능과 확장 가능성을 지원해 준 것을 확인할 수 있었습니다.

 

우선 찾아보며 생각한 것은 Hibernate의 강력한 커뮤니티와 그로 인해 나온 많은 선례, 또한 만들어진 지 오래된 만큼 안정성을 보장하기 때문이라 생각합니다.

JPA주요 특성

ORM

엔티티 클래스와 데이터베이스 테이블 간의 매핑을 지원합니다.

영속성 컨텍스트

데이터를 영속성 컨텍스트에 저장하고 지속적으로 추적하게 되는데, 이 데이터가 수정될 경우 트랜젝션이 걸려있지 않으면 바로 반영이 됩니다. 이게 무슨 의미인가 만약 데이터를 조회하여 엔티티로 받아서 바로 엔티티 속성을 수정한다면 실제 SQL문이 바로 날아가 변경된다는 뜻입니다.

 

즉 commit을 안 했는데 commit이 되는 현상으로 이러한 상황을 방지하기 위해서는 Transaction처리를 해주거나, 엔티티를 사용하지 말고 데이터를 수정할 때 사용하는 객체를 따로 만들어 해당 객체로 데이터 값들만 복사하여 사용하는 것이 안전한 사용법인 것 같습니다.

캐싱

영속성 컨텍스트는 한번 조회된 데이터들은 가지고있는데, 만약 조회되는 데이터가 영속성 컨텍스트에 저장되어있는 데이터라면 데이터베이스를 조회하지 않고 해당 데이터를 반환해줍니다. 이는 1차 캐시의 개념이며, 만약 1차 캐시에 없을 경우 2차 캐시를 조회하게되고, 거기에도 없다면 데이터베이스를 조회하게 됩니다.

 

이때 말하는 1차 캐시는 Hibernate에서 제공하는 영속성 컨텍스트 캐시이고, 2차 캐시는 Session Factory 캐시입니다.


Reference

 

Understanding EclipseLink

This chapter describes how to set up your JPA applications to work with a non-relational data source. There are many types of non-relational data sources. These include document databases, key-value stores, and various other non-standard databases, such as

eclipse.dev

 

 

JPA Getting Started Guide (v5.2)

Developing applications is, in general, a complicated task, involving many components. Developing all of these components can be very time consuming. The Java Persistence API (JPA) was designed to alleviate some of this time spent, providing an API to allo

www.datanucleus.org

 

 

What is Object/Relational Mapping? - Hibernate ORM

Idiomatic persistence for Java and relational databases.

hibernate.org

 

캐싱 참조자료: https://www.baeldung.com/hibernate-second-level-cache

 

728x90

+ Recent posts