
이전 글에서 한개의 Oracle datasource 를 붙는걸 했다.
이젠 진짜 실전에서 쓰는 Multi datasource 접속을 어떻게 하는 하겠다.
Multi datasource 접속을 위해서는 코딩이 들어간다.
그리고 첨 보는 @annotation 들이 들어간다.
1. 우선 data source 의 정보를 application.properteis 혹은 application.yml 에 작성한다.
== application.properties 를 사용할 경우 ==
# Primary DataSource
spring.datasource.primary.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.primary.username=user1
spring.datasource.primary.password=password1
spring.datasource.primary.driver-class-name=oracle.jdbc.OracleDriver
# Secondary DataSource
spring.datasource.secondary.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.secondary.username=user2
spring.datasource.secondary.password=password2
spring.datasource.secondary.driver-class-name=oracle.jdbc.OracleDriver
# MyBatis Mapper Locations (공통 설정)
mybatis.mapper-locations=classpath:mapper/**/*.xml
== application.yml 를 사용할 경우==
spring:
datasource:
primary:
url: jdbc:oracle:thin:@localhost:1521:XE
username: user1
password: password1
driver-class-name: oracle.jdbc.OracleDriver
secondary:
url: jdbc:oracle:thin:@localhost:1521:XE
username: user2
password: password2
driver-class-name: oracle.jdbc.OracleDriver
mybatis:
mapper-locations: classpath:mapper/**/*.xml
갑자기 궁금해진다 2개 아니고 3개, 4개 막 이렇게 더 쓰면 어떻게 하나 ?
그럴때마다 third, fourth 하면 되나?
맞다 그렇게 하면 되나.
==4개 쓰는 예==
# Primary DataSource
spring.datasource.primary.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.primary.username=user1
spring.datasource.primary.password=password1
spring.datasource.primary.driver-class-name=oracle.jdbc.OracleDriver
# Secondary DataSource
spring.datasource.secondary.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.secondary.username=user2
spring.datasource.secondary.password=password2
spring.datasource.secondary.driver-class-name=oracle.jdbc.OracleDriver
# Third DataSource
spring.datasource.third.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.third.username=user3
spring.datasource.third.password=password3
spring.datasource.third.driver-class-name=oracle.jdbc.OracleDriver
# Fourth DataSource
spring.datasource.fourth.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.fourth.username=user4
spring.datasource.fourth.password=password4
spring.datasource.fourth.driver-class-name=oracle.jdbc.OracleDriver
# MyBatis Mapper Locations (공통 설정)
mybatis.mapper-locations=classpath:mapper/**/*.xml
2. 1) 의 정보를 읽어서 Datasource 른 만든다.
(한개의 datasource 를 쓸때는 따로 이런 작업이 필요 없었다.)
== Primary Datasource 설정==
@Configuration
@MapperScan(basePackages = "com.example.primary.mapper", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primarySqlSessionFactory")
public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
@Primary
@Bean(name = "primarySqlSessionTemplate")
public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
== Secondary Daasource 설정 ==
@Configuration
@MapperScan(basePackages = "com.example.secondary.mapper", sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryDataSourceConfig {
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
@Bean(name = "secondarySqlSessionTemplate")
public SqlSessionTemplate secondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
이제 슬슬 짜증이 난다.
먼 골뱅이(@) 가 소스 내에 이리 많이 들어가고
@Primary 는 왜 첫번째 소스엔 있고, 두번째 에는 없는가?
@Qulifier 는 머고?
SessionFactory는 session 만드는 공장 같은데, SessionTemplate 은 또 머야?
배우기 싫다.
단군의 홍익인간으로 널리 인간을 이롭게 한다는데
밥 세끼 먹고 살기가 이리 힘들어서야.

어금니 깨물고 찬찬히..정리해보자.
더보기는 꼭 읽어야 내 지식의 피와 살이 된다.
1. @Primary 를 쓰는 이유?
: 동일한 type 의 bean 이 여러개일때 @primary 를 줘서 우선순위를 높인다.
@Primary 를 구지 않붙여도 에러는 안나지만 관습이고, 모호함을 피할수 있으니 묻고 따지지 말고 붙여라.
@Primary 붙은 녀석이 메인 DB 로 보면 된다.
2. Second Datasource 에는 @Primary 가 안 붙은 이유는?
: @Primary 붙은게 메인 DB고 Secondary는 보조니까. 당연히 안 붙지.
3. @Configuration 은 먼데? : @Component 붙이면 Spring 이 Component scan 대상으로 인식해 bean( singleton 객체)을 만들어 주는 것처럼
@Configuration 도 Bean을 만들어준다.
다만 @Configuration 을 붙인 Bean 객체는 조금 더 특별한 일을 한다는 의미를 줄수 있고,
Bean 간의 의존성을 코딩으로 주입해서 다른 Bean 들을 만든다 라고 보면 된다. 다시 말하면, Bean 간의 의존성을 관리 해서 Bean을 만드는 일을 하는 java 파일에 @Configuration을 붙이면 된다.
4. @Bean 은 먼데 ? : 주고 @Configuration 과 같이 사용 된다. 여기서는 만들어진 Bean 의 이름을 지정할때 썼다.
Spring container 가 만들어진 Bean을 관리 하는데 여기서는 Datasource 가 두개고
만들어져서 Spring container 에 담길 구조가 같은 Bean(Singleton 객체) 가 두개인데
둘다 Datasource 객체 이니 다른 Bean 들에서 의존성으로 사용 할때 구분을 주어서 사용 해야 해서
@Bean(name="primaryDataSource") @Bean(name="secondaryDataSource") 로 준거다.
5. @MapperScan?
: 쓰기도 힘들다.
Mybatis 를 쓸건데 mapper interface 는 어디에 있으니 basePackage 안에 있는걸로
mapper Interface 만들라는 뜻.
6. sqlSessionFactoryRef 는 먼데??
: sqlSessionFactoryRef="primarySqlSessionFactory" 의 의미는
" primarySqlSessionFactory "이라는 이름의 SqlSessionFactory 빈을 사용하여 지정된 패키지(-basePackage 로 에 정의한 )의 매퍼 인터페이스를 스캔하고 연결하라는 의미 이다.
7. @ConfigurationProperties(prefix = "spring.datasource.primary") 이건 머야??? : @ConfigurationProperties(prefix = "spring.datasource.primary")는 Spring Boot에서 외부 설정 파일(application.properties 또는 application.yml)의 특정 prefix를 가진 속성들을 Java 객체에 바인딩하는 역할을 한다.
즉 특정 접두사 붙은 설정 읽어서 Datsource bean을 만들어라.
8. @Qulifier 이건 먼데?
: Bean 간의 의존성 주입을 할때 같은 type의 bean 이 여러개면 그중 딱 특정한 bean을 찍어서 주입 하기 위해 씀.
여기선, @Bean(name = "primaryDataSource") 이란 이름으로 Datasource bean 객체를 만들었는데
SqlSessionFactory bean객체를 만들때 이름이 "primaryDataSource" 인 bean 객체를 매개변수로 넘겨 줘서
만든다는 의미 이다.
또 보면
SqlSessionTemplate bean 객체를 만들때 이름이 "primarySqlSessionFactor" 인 bean 객체를 매개변수로 넘겨 줘서 만든다는 의미다.
9. SqlSessionFactory 는 머고 ? SqlSessionTempate 은 또 먼가?
SqlSessionFactory와 SqlSessionTemplate는 MyBatis와 Spring을 함께 사용할 때 중요한 역할을 하는 두 가지 핵심 컴포넌트입니다.
SqlSessionFactory
SqlSessionFactory는 MyBatis에서 데이터베이스와의 연결을 설정하고 SqlSession 객체를 생성하는 역할을 합니다.주요 특징:
- 데이터베이스 연결 정보를 관리합니다.
- SqlSession 객체를 생성합니다.
- 애플리케이션 전체에서 단 하나만 존재해야 합니다 (싱글톤 패턴).
- 여러 스레드에서 공유하여 사용할 수 있습니다.
SqlSessionTemplate
SqlSessionTemplate은 MyBatis-Spring 연동 모듈의 핵심 컴포넌트로, SqlSession 인터페이스를 구현하고 SqlSession을 대체하는 역할을 합니다.주요 특징:
- 스레드에 안전하여 여러 DAO나 매퍼에서 공유할 수 있습니다.
- 스프링의 트랜잭션 관리와 연동되어 자동으로 커밋, 롤백, 세션 닫기를 처리합니다.
- SqlSession이 제공하는 메서드를 모두 제공하면서 스프링의 DataAccessException으로 예외를 변환합니다.
- 생성자의 인자로 SqlSessionFactory를 받아 생성됩니다.
차이점과 관계
- SqlSessionFactory는 SqlSession을 생성하는 팩토리 역할을 하며, SqlSessionTemplate은 SqlSession을 구현하고 확장한 클래스입니다.
- SqlSessionFactory는 MyBatis 핵심 컴포넌트이고, SqlSessionTemplate은 MyBatis-Spring 연동 모듈의 핵심 컴포넌트입니다.
- SqlSessionTemplate은 SqlSessionFactory를 통해 생성된 SqlSession을 감싸서 추가적인 기능(트랜잭션 관리, 예외 변환 등)을 제공합니다.
- 일반적으로 Spring 환경에서는 SqlSessionTemplate을 사용하여 데이터베이스 작업을 수행하며, 이는 SqlSessionFactory를 통해 생성됩니다.
SqlSessionFactory와 SqlSessionTemplate을 함께 사용함으로써, MyBatis의 강력한 데이터베이스 접근 기능과 Spring의 트랜잭션 관리 및 예외 처리 기능을 효과적으로 통합할 수 있습니다.
10. SqlSessionTemplate 이 알아서 transcation 처리를 해주는데 왜 구지 @Transactional 을 Service 를 하는 객체의 method 들에 붙이는가?
아래와 같단다 .그냥 붙여라 @TransactionalSqlSessionTemplate이 트랜잭션 처리를 자동으로 해주지만, @Transactional 어노테이션을 Service 객체의 메서드에 사용하는 것은 여러 가지 중요한 이유가 있습니다:
- 트랜잭션 범위 제어: @Transactional을 사용하면 여러 데이터베이스 작업을 하나의 트랜잭션으로 묶을 수 있습니다. 이는 여러 SqlSessionTemplate 호출을 포함하는 복잡한 비즈니스 로직에서 특히 유용합니다.
- 선언적 트랜잭션 관리: @Transactional을 사용하면 코드에서 명시적으로 트랜잭션을 시작하거나 커밋/롤백할 필요 없이 선언적으로 트랜잭션을 관리할 수 있습니다.
- 트랜잭션 속성 설정: @Transactional 어노테이션을 통해 격리 수준, 전파 동작, 타임아웃 등의 트랜잭션 속성을 세밀하게 제어할 수 있습니다.
- AOP 기반 트랜잭션 관리: 스프링은 @Transactional이 붙은 빈의 동적 프록시를 생성하여 트랜잭션을 관리합니다. 이는 비즈니스 로직과 트랜잭션 관리를 분리하여 코드의 가독성과 유지보수성을 향상시킵니다.
- 일관성 있는 트랜잭션 관리: 서비스 계층에 @Transactional을 사용함으로써 애플리케이션 전반에 걸쳐 일관된 트랜잭션 관리 방식을 적용할 수 있습니다.
- 예외 처리와 롤백: @Transactional을 사용하면 특정 예외 발생 시 자동으로 롤백되도록 설정할 수 있어, 데이터 일관성을 유지하는 데 도움이 됩니다.
따라서, SqlSessionTemplate의 자동 트랜잭션 처리 기능과 @Transactional 어노테이션은 상호 보완적으로 작용하여 더 강력하고 유연한 트랜잭션 관리를 가능하게 합니다. 서비스 계층에 @Transactional을 사용함으로써 비즈니스 로직의 트랜잭션 경계를 명확히 정의하고, 더 세밀한 트랜잭션 제어를 할 수 있습니다.
'SI 업무 > spring boot' 카테고리의 다른 글
| @Configuration 의 용도? Interface 를 어떻게 주입하지? (0) | 2024.12.26 |
|---|---|
| 5. JWT, Spring Security (0) | 2024.12.02 |
| 4. profile 로 다른 설정 관리 (0) | 2024.11.29 |
| 3. log는 어떻게 남기지? (1) | 2024.11.29 |
| 1. 한개의 data source 쓸려면 어떻게 할까? (1) | 2024.11.27 |