Mybatis를 위해 스프링이 해주는 것들

강민석·2022년 8월 22일
0

DB

목록 보기
3/4

이전 시간에는 Mybatis가 무엇인지, Mybatis의 구성요소는 무엇이 있는지에 대해 알아보았다.

앞으로는 현재 업무환경에서 사용하고 있는 Spring Boot + Batch(executor-type)에 대한 내용을 다루려고 한다.

먼저 이번 시간에는 Spring Boot에 대해 공부해보았다.

Spring Boot는 무엇을 도와줄까??

Mybatis Spring AutoConfiguration

Spring Boot가 Spring에 비해 가지는 장점은 많다. 하지만 라이브러리를 접근하는 측면이라면 가장 뚜렷한 장점으로 AutoConfiguration을 고를 수 있을 것이라고 생각한다.

AutoConfiguration: 생성하고 싶은 Bean들을 Configuration으로 지정해두어 자동으로 구성해주는 Spring Boot의 기능

AutoConfiguration으로 빈을 구성하므로서, 우리는 이전 포스팅에서 다루었던 Mybatis 구성요소들의 생명주기를 신경 쓸 필요 없이 Mybatis를 사용할 수 있게 된다.

org.mybatis.spring.boot.autoconfigure를 확인해보자.

해당 패키지에는 Mybatis의 AutoConfiguration을 위한 클래스들이 정의되어있다. 특히 MybatisAutoConfigration.class를 보면 어떤 Bean들이 Configuration되어 Bean으로 구성되는지 알 수 있다.

먼저 클래스명을 봐보자. 해당 클래스는 Configuration이므로 Spring Boot의 특성상 어노테이션만 확인해도 많은 정보를 얻을 수 있다.

@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {

위의 코드를 보면 다음의 사항들을 알 수 있다.

  1. MybatisProperties.class에 ConfigurationProperties 방식으로 설정값을 받는다
  2. SqlSessionFactory.class, SqlSessionFactoryBean.class, DataSource.class와 같은 Bean들을 조건부로 등록한다.
  3. DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class의 Configuration 등록이 끝난 후 해당 Configuration을 등록한다.

다만, 실제로 Configuration을 통해 등록되는 Bean이 어떤 것들이 있는지는 코드를 봐야 자세히 알 수 있다.

예로 간단하게 정의되어있는 SqlSessionTemplate을 확인해보자.

@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
  ExecutorType executorType = this.properties.getExecutorType();
  if (executorType != null) {
    return new SqlSessionTemplate(sqlSessionFactory, executorType);
  } else {
    return new SqlSessionTemplate(sqlSessionFactory);   
  }
}

해당 설정은 SqlSessionTemplate이 Bean으로 등록되지 않는 경우 활성화 되며(@ConditionalOnMissingBean) 앞서 언급한 MybatisProperties.class의 값에 따라 분기된다.

즉, 라이브러리의 사용자의 선택에 따라 Bean의 생성자가 선택되게 된다. executorType을 ExecutorType.BATCH와 같이 설정한 경우는 생성자의 파라미터로 들어가게 되며, null인 경우 사용하지 않는 간단한 분기이다.

이와 같은 방식으로 기존에는 개발자가 생성하고 생명주기를 관리해야했던 SqlSessionFactory, SqlSession등의 Mybatis 구성요소를 Spring Boot에서는 AutoConfiguration으로 생성하고 관리를 해준다.

이에 따라 개발자는 라이브러리를 사용하기 위한 구성요소의 생명주기를 신경쓰지 않고 원하는 기능을 사용하는 편의를 누릴 수 있게 된다.

transaction management

Spring이 제공하는 또 하나의 이점은 transaction management이다.

transaction을 개발자가 필요할 때마다 구현하려면 어떻게 해야할까?? 아마 다음과 같이 구현을 해야 할 것이다.

transaction의 구현

// 1. 커넥션 가져오기
Connection connection = dataSource.getConnection

try (connection) {
// 2. AutoCommit 설정 해제
	connection.setAutoCommit(false);
// 3. statement 실행
// 4. transaction commit
    connection.commit();
} catch (SQLException e) {
// 5. 롤백 처리
	connection.rollback();
}

개발자가 transaction을 개발 할 경우 크게 위와 같이 다섯개의 단계로 구현을 할 수 있다.

  1. database로부터 transaction을 적용시킬 connection을 가지고 온다.
  2. AutoCommit 설정을 해제한다. AutoCommit은 statement마다 commit을 바로 적용하는 database의 설정으로, transaction을 의도한다면 반드시 해제해야한다. 다른 관점으로는 AutoCommit을 true로 설정하면 매 statement 마다 개별의 transaction을 가진다고도 볼 수 있다. 위의 구현을 보면 알 수 있듯이 하나의 connection에서는 AutoCommit을 한번 설정하면 수정이 필요없다.
  3. statement를 실행한다.
  4. transaction을 commit처리한다. database에 persist, 즉 변경사항을 적용한다.
  5. SQLException이 발생한 경우, 변경사항을 rollback한다.

이렇듯 간단히 transaction의 기능을 나타낼 수 있다. 실제로 우리가 Declarative Transaction management 방식으로 transaction을 관리할 때 사용하는 @Transactional은 위와 같은 방식으로 구현이 되어있다.

Spring Declarative Transaction Management

그렇다면 스프링에서는 @Transactional을 명시하는 것과 같은 간단한 방식으로 어떻게 기능을 적용해줄까?

  1. 먼저 Spring Configuration에 @EnableTransactionManagement를 명시해주어야 한다. (Spring boot에서는 자동 적용)
  2. 원하는 Transaction manager를 Configuration에 명시한다.

위와 같이 간단한 방법으로 @Transactional의 기능을 적용할 준비를 할 수 있다. 1번의 경우 Spring boot에서 자동으로 적용을 해준다고 했고,, 그렇다면 2번은 어떻게 하면 될지 알아보자.

@Primary
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
  return new JpaTransactionManager(entityManagerFactory);
}

방법은 간단하다. Spring Configuration에 개발자가 원하는 구체적인 TransactionManager의 구현체를 명시해주면 된다.

하지만 Spring boot를 통해 @Transactional을 사용하면서 Transaction manager를 명시하지 않은 개발자들이 많을 것이다. 별도의 설정없이 우리의 어플리케이션은 어떻게 동작하고 있을까라는 고민을 자연스레 하게되었다.

이유는 아주 간단했다. 초기에 설명했던 AutoConfiguration이 바로 그 답이였다. mybatis-spring-boot-starter-x.jar를 보면 xml로 작성된 dependency file인 pom.xml이 있다. 해당 파일을 보자.

...
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
...

위와 같이 spring-boot-starter-jdbc 의존성이 있는 것을 확인할 수 있다.

Spring Boot의 경우, spring-boot-autoconfigure에서 모든 spring-boot-starter-x의 설정을 책임지고 있으므로 해당 패키지를 확인해보았다. org.springframework.boot.autoconfigure.jdbc내의 DataSourceTransactionManagerAutoConfiguration이 그동안 찾던 해답을 가지고 있었다.

@Bean
@ConditionalOnMissingBean(TransactionManager.class)
DataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,
		ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
	DataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);
	transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
	return transactionManager;
}

결국 mybatis를 사용할 때, Spring Boot에 의해 mybatis의 의존성과 jdbc의 의존성을 모두 주입받게 되고 이 때 이루어지는 자동설정으로 TransactionManager가 확정된다. 덕분에 우리는 Spring boot를 사용하면 별도의 설정없이도 @Transactional을 사용할 수 있다.

0개의 댓글