강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

정서현님의 프로필 이미지
정서현

작성한 질문수

@Transactional과 MULTI_TENANT_CONNECTION_PROVIDER, MULTI_TENANT_IDENTIFIER_RESOLVER 동작

작성

·

25

0

Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
properties.put(MultiTenancySettings.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(MultiTenancySettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);

// MultiTenantConnectionProvider 중 커넥션 획득 메서드
@Override
    public Connection getAnyConnection() throws SQLException {
        return routingDataSource.getConnection();
    }


이번 JPA, Hibernate 사용 중 다중 스키마 지원을 위해 멀티태넌시를 도입했습니다. 그런데 커넥션 프로바이더의 커넥션 획득 타이밍과 트랜잭션의 타이밍이 다른 것인지, @Transactional 의 readOnly 값이 나중에 적용되어, 커넥션 자체는 readWrite로 지정되고 계속 rw DB에 I/O가 가더라구요

혹시 이 문제 해결 방법이 있을까요?

ThreadLocal에 라우팅 키를 지정해서 그것을 기반으로 하는 것도 진행해봤으나, 그 부분에서도 propagaion = REQUIRED_NEW인 경우 새로운 커넥션을 열어 readWrite로 향해야 하는 것이 readOnly로 향해서 데이터 수정에 실패하는 케이스도 확인했습니다

Hibernate 설계 의도에 맞춰 해결할 수 있는 방법이 있는지 궁금해요
알고 계신 방법 있다면 조언 부탁드립니다.

 

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.
정서현님께서 문의하신 Hibernate와 JPA의 Multi-tenancy 및 @Transactional을 사용한 트랜잭션 관리 문제와 관련된 해결 방법을 함께 살펴보겠습니다.

  1. @Transactional(readOnly = true) 사용시 문제:

    • @Transactional에서 readOnly 옵션을 사용하면 Hibernate가 특정 데이터베이스 최적화를 시도합니다. 이로 인해 커넥션이 읽기 전용 모드로 열릴 수 있습니다. 하지만 Multi-tenancy 구성에서 모든 트랜잭션의 기본 설정은 데이터베이스 연결 전에 결정되어야 합니다.
  2. 트랜잭션의 타이밍과 연결 타이밍:

    • Multi-tenant 환경에서 동일한 데이터소스가 다양한 테넌트(스키마)를 지원하고, Hibernate가 각각의 트랜잭션 앞에 언제 어떤 연결을 해야하는지는 중요한 문제입니다.
    • getAnyConnection() 메서드에서 단순히 연결을 반환하는 방식이 아닌, 테넌트 구분의 역할을 명확히 하고 해당 테넌트를 기반으로 적절한 연결을 반환하는 방식으로 변경해야 합니다.
  3. ThreadLocal을 사용한 해결책:

    • ThreadLocal을 사용하여 현재 트랜잭션에서의 테넌트 정보를 유지하고 이를 통해 현재 테넌트의 데이터소스를 명확히 선택하는 방법이 일반적입니다.
    • 그러나 propagation = REQUIRED_NEW인 경우 새로운 트랜잭션이 생성되며, 이 때 이전의 ThreadLocal 설정이 반영되지 않을 수 있습니다. 이 경우 새로운 연결이 그때의 설정을 따르도록 별도의 TransactionSynchronization을 이용하거나, 트랜잭션의 종료 시점에 ThreadLocal을 초기화하여 새롭게 적용할 수 있도록 해야 합니다.
  4. Hibernate의 Custom Connection Provider 사용:

    • 커스터마이즈된 MultiTenantConnectionProvider를 통해 각 트랜잭션 컨텍스트에 따라 적절한 데이터베이스 연결을 명확히 선택할 수 있도록 설정을 재구성하는 것도 방법입니다.

정리하자면, Multi-tenancy 환경에서의 @Transactional의 선정적 타이밍 문제를 해결하기 위해서는 트랜잭션 라이프사이클에 맞춰 ThreadLocal이나 커스텀 Connection Provider를 적절히 활용하는 것이 중요합니다. 이를 통해 모든 트랜잭션이 올바른 모드로 작동할 수 있도록 설정해줘야 합니다.

도움이 되었기를 바랍니다. 추가적으로, Spring Data JPA의 트랜잭션 관련 문서도 함께 참고하시면 보다 구체적인 이해에 도움이 될 것입니다.

정서현님의 프로필 이미지
정서현
질문자

MultiTenantConnectionProvider 를 커스텀해서 적용하는 것도 방법이라면 어떤 방식이 있을까요?

제가 커넥션 프로바이더에 행했던 방식은 아래와 같습니다
@Override public Connection getAnyConnection() throws SQLException { return (TransactionSynchronizationManager.isCurrentTransactionReadOnly() ? slaveDataSource : masterDataSource).getConnection(); }
그런데 커넥션 프로바이더 내에서 TransactionSynchronizationManager.isCurrentTransactionReadOnly() 메서드가 호출되었을때는 readOnly 플래그가 false인 경우가 대부분인 것 같아요

아마 커넥션 프로바이더의 커넥션 획득 시점과 트랜잭션 인터셉터가 readOnly 플래그를 업데이트하는 시점에 차이가 발생한 것 같은데, 맞을까요? 커넥션 프로바이더가 들어가며 생긴 문제라 둘의 커넥션 획득 시점 차이가 생긴 이유가 궁금해요

정서현님의 프로필 이미지
정서현

작성한 질문수

질문하기