Spring/Spring

[Spring][Data Access] 1-2. Transaction Manager: Understanding the Spring Framework Transaction Abstraction

noahkim_ 2024. 8. 11. 06:01

1. Transaction Stretegy

  • Spring이 트랜잭션을 어떻게 처리할지 정의
  • TransactionManager 인터페이스에서 담당

 

2. TrasactionDefinition

  • 트랜잭션의 동작 방식 정의
더보기
public interface TransactionDefinition {

	int PROPAGATION_REQUIRED       = 0; 
	int PROPAGATION_SUPPORTS       =  1;
	int PROPAGATION_MANDATORY      =  2;
	int PROPAGATION_REQUIRES_NEW   =  3;
	int PROPAGATION_NOT_SUPPORTED  =  4;
	int PROPAGATION_NEVER          =  5;
	int PROPAGATION_NESTED         =  6;

	int ISOLATION_DEFAULT          = -1;  // 데이터베이스 기본 격리 수준 사용
	int ISOLATION_READ_UNCOMMITTED =  1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;
	int ISOLATION_READ_COMMITTED   =  2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;
	int ISOLATION_REPEATABLE_READ  =  4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;
	int ISOLATION_SERIALIZABLE     =  8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;

	int TIMEOUT_DEFAULT = -1;

	default int getPropagationBehavior() { return PROPAGATION_REQUIRED; }			
	default int getIsolationLevel() { return ISOLATION_DEFAULT; }			
	default int getTimeout() { return TIMEOUT_DEFAULT; }			
	default boolean isReadOnly() { return false; }
		
	@Nullable
	default String getName() { return null; }
		
	static TransactionDefinition withDefaults() { return StaticTransactionDefinition.INSTANCE; }
}

 

 

Propagation

  • 트랜잭션이 다른 트랜잭션 컨텍스트 내에서 어떻게 동작해야 하는지 설정하는 방법

 

REQUIRED
  • 외부 트랜잭션 O: join
  • 외부 트랜잭션 X: 새 트랜잭션 시작

 

SUPPORTS
  • 외부 트랜잭션 O: join
  • 외부 트랜잭션 X: 트랜잭션 없이 실행

 

MANDATORY
  • 외부 트랜잭션 O: join
  • 외부 트랜잭션 X: 예외 발생 (IllegalTransactionStateException)

 

REQUIRES_NEW
  • 외부 트랜잭션 O: 새 트랜잭션 시작 (외부 트랜잭션 일시 정지)
  • 외부 트랜잭션 X: 새 트랜잭션 시작 

 

NOT_SUPPORTED
  • 외부 트랜잭션 O: 트랜잭션 없이 실행 (외부 트랜잭션 일시 정지)
  • 외부 트랜잭션 X: 트랜잭션 없이 실행

 

NEVER
  • 외부 트랜잭션 O: 예외 발생 (IllegalTransactionStateException)
  • 외부 트랜잭션 X: 새 트랜잭션 시작

 

NESTED
  • 외부 트랜잭션 O: 중첩 트랜잭션 시작 (부모 트랜잭션에 중첩 트랜잭션의 Savepoint 생성됨)
    • 부모 트랜잭션 예외 시: 중첩 트랜잭션 모두 롤백됨
    • 중첩 트랜잭션 예외 시: 중첩 트랜잭션 Savepoint까지 수행됨 (부모 트랜잭션 계속 동작)
  • 외부 트랜잭션 X: 새 트랜잭션 시작 

 

Isolation

  • 트랜잭션이 다른 트랜잭션으로 얼마나 독립적으로 동작하는지 정의
  • 레벨이 높아질수록 데이터 무결성은 높아지지만, 성능상 비용이 많이 듬

 

READ_UNCOMMITTED
  • 트랜잭션이 커밋하지 않은 데이터도 읽을 수 있음
  • 문제점: Dirty Read, Non-repeatable Read, Phantom Read

 

READ_COMMITTED
  • 트랜잭션이 커밋된 데이터만 읽을 수 있음
  • 문제점: Non-repeatable Read, Phantom Read

 

REPEATABLE_READ
  • 읽기 잠금: 트랜잭션이 읽고 있는 자원을 다른 트랜잭션에서 수정 및 삭제 불가
  • 문제점: Phantom Read

 

Serializable
  • 읽기 잠금: 트랜잭션이 읽고 있는 자원을 다른 트랜잭션에서 수정 및 삭제 불가
  • 쓰기 잠금: 트랜잭션이 수정하거나 삭제하려는 자원을 다른 트랜잭션에서 읽기, 수정 및 삭제 불가
  • 문제점: 성능

 

 

Timeout

  • 트랜잭션이 얼마나 오래 실행될 수 있는지 설정

 

Read-only

  • 트랜잭션이 데이터 읽기만 할지 여부 결정

 

3. TrasactionStatus

트랜잭션 상태
  • isNewTransaction(): 새로 생성된 트랜잭션 여부 (새로 시작된 것인지, 외부 트랜잭션에 참여한 것인지)
  • isRollbackOnly(): 롤백 전용 여부
  • isCompleted(): 완료 여부

 

트랜잭션 동작
  • flush(): 모든 쓰기 작업을 db에 강제로 반영

 

트랜잭션 설정
  • setRollbackOnly(): 현재 트랜잭션을 롤백 전용으로 설정 (커밋 X, 반드시 롤백 전용으로 설정)

 

더보기
@Service
public class ExampleService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void performTransactionalOperation() {
        // 트랜잭션 정의 생성
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        // 트랜잭션 시작
        TransactionStatus status = transactionManager.getTransaction(definition);

        try {
            // 트랜잭션이 새로운 것인지 확인
            if (status.isNewTransaction()) {
                System.out.println("새로운 트랜잭션이 시작되었습니다.");
            }

            // 데이터베이스 작업 수행
            jdbcTemplate.update("INSERT INTO my_table (column1) VALUES (?)", "Test Value");

            // 플러시를 통해 쓰기 작업을 강제로 데이터베이스에 반영
            status.flush();

            // 비즈니스 로직에 따른 롤백 전용 설정
            if (/* 어떤 조건 */) {
                status.setRollbackOnly();
            }

            // 롤백 전용 상태인지 확인
            if (status.isRollbackOnly()) {
                System.out.println("트랜잭션은 롤백 전용 상태로 설정되었습니다.");
                // 명시적으로 롤백
                transactionManager.rollback(status);
                return;
            }

            // 트랜잭션 커밋
            transactionManager.commit(status);
            System.out.println("트랜잭션이 성공적으로 커밋되었습니다.");
        } catch (Exception e) {
            // 예외 발생 시 트랜잭션 롤백
            transactionManager.rollback(status);
            System.out.println("트랜잭션이 롤백되었습니다.");
        }
    }
}

 

4. TransactionManager (PlatformTransactionManager)

  • 트랜잭션 관리의 핵심 (Spring)
  • 선언적으로 사용됨 (설정 및 관리)
더보기
public interface PlatformTransactionManager extends TransactionManager {

	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

	void commit(TransactionStatus status) throws TransactionException;

	void rollback(TransactionStatus status) throws TransactionException;

}

 

Implementataion

DataSourceTransactionManager
  • JDBC 기반 데이터 소스
  • Local Transaction

 

HibernateTransactionManager
  • Hibernate와 연동된 트랜잭션 관리 담당 (start, commit, rollback)
  • SessionFactory와 연동
  • Local Transaction
더보기
@Configuration
@EnableTransactionManagement // 트랜잭션 관리 활성화
public class AppConfig {

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory().getObject());
        return txManager;
    }
}

 

JtaTransactionManager
  • Global Transaction
더보기
@Bean
public JtaTransactionManager transactionManager() {
    return new JtaTransactionManager();
}

 

장점

추상화
  • 기술, 트랜잭션 종류와 상관없이 코드 작성이 동일

 

비침투적

 

5. Hibernate

LocalSessionFactoryBean

  • SessionFactory 설정 및 초기화
  • Spring 컨테이너에 의해 트랜잭션을 관리할 수 있음 (PlatformTransactionManager와 통합됨)
더보기
@Configuration
@EnableTransactionManagement
public class HibernateConfig {

    @Autowired
    private DataSource dataSource; // DataSource는 DB 연결을 관리

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setPackagesToScan("com.example.myapp.entity"); // 엔티티 클래스가 있는 패키지 설정
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public PlatformTransactionManager hibernateTransactionManager(SessionFactory sessionFactory) {
        return new HibernateTransactionManager(sessionFactory);
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.format_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "update");
        return properties;
    }
}

 

6. JPA

LocalContainerEntityManagerFactoryBean

  • JPA의 EntityManagerFactory 설정
  • Hibernate와 JPA의 설정이 통합됨
더보기
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setPackagesToScan("com.example.myapp.entity"); // JPA 엔티티 클래스 패키지 스캔

    // Hibernate JPA 공급자 설정
    em.setJpaVendorAdapter(new org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter());

    return em;
}

 

7. DataSource

  • 데이터베이스 연결 관리

 

 


출처