Backend/Spring+Boot

Spring DB 연동

findmypiece 2021. 3. 12. 17:24
728x90

SpringBoot 에서는 너무 많은 것을 자동으로 처리해주기 때문에

여기에서는 이해를 위해 Spring에서 JavaConfig로 직접 연동하는 법을 알아보자.

 

다만 Jpa 가 활성화 되기 시작했을 무렵 SpringBoot도 함께 활성화 되었고

Jpa를 사용하는 프로젝트는 대부분 SpringBoot를 사용할 것이다.

반면 Mybatis는 SpringBoot가 나오기 전부터 사용되던 전통적인 퍼시스턴스 프레임워크로

레거시 시스템들은 Spring+Mybatis 로 되어 있는 경우도 적지 않다.

 

이에 여기에서는 Mybatis만 연동 벙법만 살펴보고

추후 SpringBoot DB 연동에서는 Mybatis와 Jpa를 함께 살펴보도록 한다.

 

우선 Configuration 파일은 아래와 같이 정의한다.

@Configuration 
@EnableTransactionManagement 
public class MybatisConfig { 

  @Bean
  @ConfigurationProperties(prefix = "datasource")
  public DataSource dataSource() {
    return DataSourceBuilder.create().type(HikariDataSource.class).build();
  }

  @Bean 
  public PlatformTransactionManager transactionManager(DataSource dataSource) { 
    return new DataSourceTransactionManager(dataSource); 
  }
    
  @Bean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource)throws Exception{
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(dataSource);

    Resource[] res = new PathMatchingResourcePatternResolver()
    					.getResources("classpath:mapper/*Mapper.xml");

    sessionFactory.setMapperLocations(res);

    return sessionFactory.getObject();
  }
 
  @Bean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
      return new SqlSessionTemplate(sqlSessionFactory);
  }
  
}

application.yml 파일은 아래와 같을 것이고

datasource:
	driver-class-name: com.mysql.cj.jdbc.Driver #runtimeOnly 의존성만 있으면 된다.
	jdbc-url: jdbc:mysql://127.0.0.1:3306/TEST
	username: test
	password: test

SQL을 정의한 xml 파일은 src/resources/mybatis 디렉토리 하위에 

*Mapper.xml 과 같은 패턴의 파일명으로 생성해서 아래와 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
 
<mapper namespace="com.test">
 
    <select id="getUserList" resultType="hashmap">
        select id, name 
        from user_info
        limit 10
    </select>
 
</mapper>

실제 Service 단에서 사용은 아래와 같이 한다.

package com.test;

...

@Repository
@RequiredArgsConstructor
public class MainDAO {
  private final SqlSession sqlSession;    
  private static final String MAPPER_NM = "com.test.";

  public List<Map> getUserList(){
  	return sqlSession.selectList(MAPPER_NM+"getUserList");
  }
}

신기한 것은 SqlSession 이라는 빈은 생성하지 않았는데 어떻게 자동주입이 발생하는 것인가?

결국 MybatisConfig 에서 생성한 SqlSessionTemplate 빈이 주입되는 것인데

SqlSessionTemplate이 내부적으로 SqlSession을 구현한다.

 

이어서 MybatisConfig 설정을 하나씩 들여다보자.

DataSource 빈은 application.yml 에서 DB접속정보를 읽어와서 커넥션풀을 생성한다.

그럼 커넥션 풀 사이즈 같은 건 어디에 정의하나?

application.yml 에 추가로 정의해도 되지만 설정하지 않을 경우 

HikariConfig 에 있는 아래 초기값이 할당된다.

 

PlatformTransactionManager 빈을 생성하는 부분은 트랜잭션 관리자를 정의하는 부분이다.

실제로 코드상에서 @Transactional 어노테이션을 통해 트랜잭션을 적용할 수 있다.

주의할 점은 PlatformTransactionManager 빈을 생성하는 메소드 이름이 반드시 

transactionManager 여야 한다는 점이다.

 

@Transactional 이 찾는 빈 name이 transactionManager 이기 때문인데

Spring에서 @Bean 어노테이션으로 빈을 생성할 때 name 속성을 지정하지 않을 경우

기본적으로 해당 메소드의 이름이 빈 name이 된다.

만약 PlatformTransactionManager 빈 생성 메소드명을 txManager 같은 걸로 했다면

아래 방법 중 하나를 선택적으로 적용해야 한다.

//생성되는 빈 이름을 지정하던가
@Bean(name="transactionManager")
public PlatformTransactionManager txManager(DataSource dataSource) { 
	return new DataSourceTransactionManager(dataSource); 
}
//@Transactional 어노테이션 사용시 빈 이름을 지정하던가
@Transactional(value = "txManager")

 

마지막으로 또 한가지 살펴볼 것은 @EnableTransactionManagement 어노테이션이다.

결론부터 말하면 이건 @Transactional 를 사용하기 위한 필수 설정이다.

트랜잭션은 실제 코드에서 클래스 혹은 메서드에 상단에 @Transactional를 명시해서 사용하게 된다.

@EnableTransactionManagement 이 설정이 없어도 @Transactional 을 사용하는데에는 

컴파일이나 런타임시 아무런 문제가 되진 않지만 우리가 원하는 트랜잭션 처리는 되지 않는다.

 

@EnableTransactionManagement 는 결국 과거 Spring의 xml 설정방식에서 사용되던

<tx:annotation-driven/> 와 동일한 역할을 해주는 것인데 

Spring 런타임에서 @Transactional 를 인지해서 실제 트랜잭션 처리를 할 수 있도록 해주는 역할을 한다.

Spring에서 트랜잭션 처리 자체가 AOP를 활용하기 때문에 아마도 여기에서 사용되지 않을까 싶다.

다르게 말하면 @EnableTransactionManagement 설정이 없는 상태에서 정의하는 

@Transactional 은 아무런 의미가 없다는 말이다.

 

참고로 나중에 SpringBoot DB 연동을 하며 정리하겠지만

SpringBoot 사용한다면 @EnableTransactionManagement 이 자동설정에 포함되어 있기 때문에

위와 같이 명시적으로 추가하지 않아도 된다.

 

SqlSessionFactory, SqlSessionTemplate 빈 생성이 Mybatis 연동을 위한 빈이다.

Service 단에서 실제 DB 조작을 위해서는 결국 SqlSession 이 필요한데

DataSource와 SQL을 정의한 xml 로 SqlSessionFactory 를 만들고
SqlSesssionTemplate 에서는 SqlSessionFactory 를 통해 SqlSession 빈을 만드는 것이다.

 

참고로 Ibatis의 경우도 이와 비슷하게 Factory와 Template이 필요했는데

SqlMapClientFactoryBean 에서 DataSource와 SQL을 정의한 xml로 SqlMapClient 를 만들고

이렇게 만들어진 SqlMapClient 와 DataSource 를 통해 

SqlMapClientTemplate 를 생성하는 방식이 이었다.

728x90