Java/Spring

DataSoruce TransactionManager 설정(commit, rollback)

Z_Z 2024. 9. 12. 14:02
반응형

환경 : Spring Boot 6, HikariDataSource 사용

 

데이터베이스 Insert 및 Update 하는 과정에서 예외가 발생된다면 해당 과정들의 데이터를 다시

rollback 해야 하는 상황이 나타난다.

 

이러한 과정에서 예외가 발생하지 않았을 때 최종적으로 Insert 및 Update 를 하고

예외가 발생했을 때 rollback 하기 위해선 Spring 에서 제공하는 Transaction 기술을 사용해야한다.

자세한 내용은 Spring 공식문서에 나와있다.

 

https://docs.spring.io/spring-framework/reference/data-access/transaction/strategies.html

 

Understanding the Spring Framework Transaction Abstraction :: Spring Framework

You can also easily use Hibernate local transactions, as shown in the following examples. In this case, you need to define a Hibernate LocalSessionFactoryBean, which your application code can use to obtain Hibernate Session instances. The DataSource bean d

docs.spring.io

 

 

Transaction 을 처리하기 위해선 TransactionManager 를 사용한다.

TransactionManager 인터페이스를 실제로 들어가보면 비어있으며, TransactionManager 를 상속받은

PlatformTransactionManager 인터페이스를 사용하라고 공식문서에 나와있다.

PlatformTransactionManager 는 트랜잭션 관리 추상화 클래스이다.

 

PlatformTransactionManager 인터페이스를 구현하는 메서드는 총 3가지이다.

  • Transaction 을 가지고 오는 getTransaction()
  • DB 처리에 예외가 없고 모두 성공했다면 commit()
  • 예외 발생 시 rollback 을 위한 rollback()
public interface PlatformTransactionManager extends TransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;
}

 

 

 

여기서 우리는 DataSource 를 이용하여 Transaction 을 처리한다.

PlatformTransactionManager 인터페이스를 구현한 구현체인 DataSourceTransactionManager 클래스를 이용한다.

 

@SuppressWarnings("serial")
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
	@Nullable
	private DataSource dataSource;
    
	public DataSourceTransactionManager() {
		setNestedTransactionAllowed(true);
	}
    
	public DataSourceTransactionManager(DataSource dataSource) {
		this();
		setDataSource(dataSource);
		afterPropertiesSet();
	}
    
    ...
}

 

 

위 DataSouraceTransactionManager 를 Bean 등록하여 사용해보자.

 

공식문서에서는 xml 에 bean 등록해서 사용하는 방법이 나와있다.

 

공식문서 XML Bean 설정방법

 

설정한 DataSource 를 DataSourceTransactionManager 에 설정하여 Bean 등록을 한다.

 

 

DataSourceTransactionManager Bean 설정

본인은 HikariDataSource 를 사용했으며, 설정은 아래와 같다.

@Configuration
@MapperScan(basePackages = "com.league.mapper")
public class DBConfig {
	
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariConfig hikariConfig() {
    	return new HikariConfig();
    }

    @Bean
    public HikariDataSource dataSource() {
    	return new HikariDataSource(hikariConfig());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource());
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/league/mapper/**/*.xml"));
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSession() throws Exception {
    	return new SqlSessionTemplate(sqlSessionFactory());
    }

    @Bean
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

 

 

DataSourceTransactionManager 에 dataSource 를 파라미터로 넘겨 Bean 등록을 한다.

추가한 내용은 아래와 같다.

@Bean
public DataSourceTransactionManager transactionManager() {
	return new DataSourceTransactionManager(dataSource());
}

 

 

PlatformTransactionManager 사용 예시

이제 설정한 TransactionManager 를 사용하기 위해 Service 단에 PlatformTransactionManager 를

주입받아 사용해보자. 본인은 @Autowired 를 사용하지 않고 생성자 주입방식으로 주입했다.

 

@Service
public class LeagueService {
	
    private final SqlSessionTemplate sqlSession;
    private final PlatformTransactionManager tm;

    public LeagueService(SqlSessionTemplate sqlSession, PlatformTransactionManager tm) {
        this.sqlSession = sqlSession;
        this.tm = tm;
    }
    
    ....
}

 

 

등록한 PlatformTransactionManager 를 사용해보자

getTransaction(new DefaultTransactionDefinition()) 을 통해서 현재 Transaction 을 가져온다.

DB  Transaction 에 예외가 발생하지 않았을경우 성공이라고 보고 commit 을 한다.

Exception 부분에 예외 발생 시 rollback 을 위한 Transaction rollback() 를 통해 rollback 한다.

public void authTest() {
    LeagueMapper mapper = sqlSession.getMapper(LeagueMapper.class);
    TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition());

    try {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("user_name", "obo2");
        map.put("user_pw", "1234");
        map.put("role", "MAMBER");
        mapper.insertTest(map);

        map.clear();
        map.put("user_name", null);
        map.put("user_pw", "1234");
        map.put("role", "MANAGER");

        mapper.insertTest(map);
        tm.commit(ts);
        System.out.println("commit 완료");
	} catch (Exception e) {
        tm.rollback(ts);
        System.out.println("rollback 완료");
        e.printStackTrace();
    }

}

 

 

 

반응형