spring boot my batis 다 중 데이터 원본

실제 개발 에서 우리 의 한 프로젝트 는 여러 개의 데이터 베 이 스 를 사용 할 수 있 고 보통 하나의 데이터 베 이 스 는 하나의 데이터 소스 에 대응 할 수 있다.
spring boot 프로젝트 에서 시스템 기본 값 은 applicationContext 에 dataSource 의 bean 을 자동 으로 등록 합 니 다. DataSource. class 의 인 스 턴 스 를 정의 하면 이 bean 을 덮어 씁 니 다.그러나 여러 개의 DataSource. class 인 스 턴 스 를 정의 하면 시작 할 때 실례 화 된 mapper 를 제시 할 때 여러 개의 datasource 를 발견 하여 시작 에 실 패 했 습 니 다.
먼저 단일 데이터 원본 의 설정 사례 를 살 펴 보 겠 습 니 다.
1. 단일 데이터 소스 현황
1.1、MyBatisConfiguration
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@ConditionalOnClass({EnableTransactionManagement.class})
@MapperScan(basePackages={"com.roy.**.mapper"})
public class MyBatisConfiguration {

    @Autowired
    private DataSource dataSource;

    public DataSource dataSource() {
        return dataSource;
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/**/*.xml"));
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        sqlSessionFactoryBean.setConfiguration(configuration);
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }


}

1.2、application.properties
#        
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@//127.0.0.1:1521/testdb
spring.datasource.username=test
spring.datasource.password=test
#            ,           
#      ,  ,  
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
#              
spring.datasource.maxWait=60000
#              ,           ,     
spring.datasource.timeBetweenEvictionRunsMillis=60000
#                 ,     
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
#   PSCache,         PSCache   
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
#          filters,       sql    ,'wall'     
spring.datasource.filters=stat,wall,log4j
#   connectProperties     mergeSql  ; SQL  
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#     DruidDataSource     
#spring.datasource.useGlobalDataSourceStat=true

다 중 데이터 소스 다 중 데이터 소스 로 개조 하 는 주요 실현 원 리 는 DataSource 인터페이스의 실현, getConnection () 과 unwrap () 방법 을 재 작성 하 는 것 입 니 다. 여기 서 다 중 데이터 소스 datasource 에 대한 선택 전환 을 실현 하고 SqlSession Factory 와 PlatformTransactionManager 에 등록 합 니 다.저 희 는 AbstractRouting DataSource 류 를 참고 하여 여러 datasource 의 기능 을 지원 하 는 것 을 발 견 했 습 니 다. 저 희 는 proctected abstract Object determineCurrentLookupkey () 만 실현 하면 됩 니 다.방법 으로 datasource 를 전환 하면 됩 니 다.이 를 위해 우 리 는 인터넷 예 를 참고 하여 위의 단일 데이터 소스 를 다음 과 같이 조정 하여 다 중 데이터 소스 를 지원 합 니 다.
2. 다 중 데이터 소스 현황
2.1 새로운 DynamicDataSource 클래스 계승 AbstractRoutingDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseName();
    }
}

2.2, 새 DatabaseContextHolder, 스 레 드 변 수 를 이용 하여 현재 데이터 원본 의 key 값 을 저장 합 니 다 (여기 서 dataSource 인 스 턴 스 의 beanName 을 key 값 으로 사용 합 니 다)
public class DatabaseContextHolder {

    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    public static void setDatabaseName(String type){
        contextHolder.set(type);
    }

    public static String getDatabaseName(){
         return contextHolder.get();
    }

    public static void clear() {
        contextHolder.remove();
    }

}

2.3 위의 MyBatisConfiguration 클래스 를 개조 하고 dataSource () 방법 을 다시 씁 니 다.
    @Autowired
    private DataSource dataSource;

    public Map otherDataSources() {
        return null;
    }

    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map targetDataSources = new HashMap<>();
        targetDataSources.put("dataSource", dataSource);
        if (otherDataSources()!=null) {
            for (String key : otherDataSources().keySet()) {
                targetDataSources.put(key, otherDataSources().get(key));
            }
        }
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(dataSource);
        dynamicDataSource.afterPropertiesSet();
        return dynamicDataSource;
    }

주의: 여기 서 저 는 인터넷 에서 여러 개의 DataSource. class 의 bean 을 applicationContext 로 예화 하 는 방식 을 사용 하지 않 았 습 니 다. 제 실제 검증 을 통 해 applicationContext 안에 여러 개의 DataSource. class 의 bean 이 있 으 면 mapper 의 bean 을 생산 할 때 모두 잘못 보고 할 수 있 습 니 다 (제 구조 상 어디 에 제한 이 있 는 지 모 르 는 것 일 수도 있 습 니 다).그래서 저 는 특별한 방식 으로 Public Map otherDataSources () {return null;} 의 방법 을 추 가 했 습 니 다. 여러 개의 DataSource 가 있 으 면 이 안에 new 가 나 오고 applicationContext 에 주입 되 지 않 습 니 다.
2.4. DataSource 를 어떻게 자체 적 으로 예화 하 는 지 다음 과 같은 것 을 참고 하 십시오. 여기 서 저 희 는 DruidDataSource 를 사용 합 니 다.
    @Value("${second.datasource.url}")
    private String dbUrl;
    @Value("${second.datasource.username}")
    private String username;
    @Value("${second.datasource.password}")
    private String password;
    @Autowired
    protected DataSourceProperties dataSourceProperties;

    public static final String DATASOURCE_SECOND_KEY="secondDataSource";

    public Map otherDataSources() {
        Map map = new HashMap<>();
        map.put(DATASOURCE_SECOND_KEY, secondDataSource());
        return map;
    }

    public DataSource secondDataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(dataSourceProperties.getDriverClassName());
        datasource.setInitialSize(dataSourceProperties.getInitialSize());
        datasource.setMinIdle(dataSourceProperties.getMinIdle());
        datasource.setMaxActive(dataSourceProperties.getMaxActive());
        datasource.setMaxWait(dataSourceProperties.getMaxWait());
        datasource.setTimeBetweenEvictionRunsMillis(dataSourceProperties.getTimeBetweenEvictionRunsMillis());
        datasource.setMinEvictableIdleTimeMillis(dataSourceProperties.getMinEvictableIdleTimeMillis());
        datasource.setValidationQuery(dataSourceProperties.getValidationQuery());
        if (dataSourceProperties.getTestWhileIdle()!=null) {
            datasource.setTestWhileIdle(dataSourceProperties.getTestWhileIdle());
        }
        if (dataSourceProperties.getTestOnBorrow()!=null){
            datasource.setTestOnBorrow(dataSourceProperties.getTestOnBorrow());
        }
        if (dataSourceProperties.getTestOnReturn()!=null) {
            datasource.setTestOnReturn(dataSourceProperties.getTestOnReturn());
        }
        if (dataSourceProperties.getPoolPreparedStatements()!=null) {
            datasource.setPoolPreparedStatements(dataSourceProperties.getPoolPreparedStatements());
        }
        if (dataSourceProperties.getMaxPoolPreparedStatementPerConnectionSize()!=null) {
            datasource.setMaxPoolPreparedStatementPerConnectionSize(dataSourceProperties.getMaxPoolPreparedStatementPerConnectionSize());
        }
        if (dataSourceProperties.getConnectionProperties()!=null) {
            datasource.setConnectionProperties(dataSourceProperties.getConnectionProperties());
        }
        if (dataSourceProperties.getUseGlobalDataSourceStat()!=null) {
            datasource.setUseGlobalDataSourceStat(dataSourceProperties.getUseGlobalDataSourceStat());
        }
        try {
            datasource.setFilters(dataSourceProperties.getFilters());
        } catch (SQLException e) {
            logger.error("dataSource configuration initialization filter", e);
        }
        return datasource;
    }

그 중에서 DataSourceProperties 류 는 application. properties 를 주입 한 spring. datasource 의 매개 변수 입 니 다.
2.5, application. properties 에 두 번 째 datasource 설정 을 추가 합 니 다.
second.datasource.url=jdbc:oracle:thin:@//127.0.0.1:1521/testdb2
second.datasource.username=test2
second.datasource.password=test2

2.6 사용 방법
//        
        City city = cityService.getCityById(id,null);
//            
        DatabaseContextHolder.setDatabaseName(MyBatisConfiguration.DATASOURCE_SECOND_KEY);
        city = cityService.getCityById(id,null);
        DatabaseContextHolder.clear();

위 와 같이 우 리 는 두 개의 라 이브 러 리 에 city 표를 만 들 고 모두 city Id = 1 의 기록 을 설정 합 니 다. 첫 번 째 라 이브 러 리, city Name = 심 천, 두 번 째 라 이브 러 리, city Name = 로스앤젤레스.위의 두 번 의 요청 을 통 해 돌아 온 city Name 결 과 는 예상 한 대로 데이터 원본 이 정상적으로 전환 되 었 음 을 설명 합 니 다.메모: DataSource 를 전환 할 때마다 DatabaseContextHolder. clear () 를 사용 하 십시오.방법 은 스 레 드 변 수 를 비 웁 니 다.
후속
1. 위 에 적 힌 것 은 applicationContext 에 여러 개의 DataSource. class 의 bean 이 있 으 면 시작 할 때 mapper 타 임 스 를 생 성 하 는 오류 가 발생 할 수 있 습 니 다.그 중 하나 인 DataSource 의 bean 에 @ Primary 주 해 를 추가 하면 2, 이상 dataSource () 방법 을 덮어 쓰 고 돌아 오 는 DataSource 의 인 스 턴 스 는 DynamicDataSource 의 인 스 턴 스 로 전체 프로젝트 의 업무 가 실 효 될 수 있 으 므 로 시스템 에 업무 가 필요 한 곳 이 있 으 면 다 중 데이터 원본 설정 을 신 중 히 사용 해 야 합 니 다.다 중 데이터 소스 가 비교적 적합 한 장면 은 데이터 분석 이 고 대부분 은 논 리 를 조회 하고 서로 다른 라 이브 러 리 의 데 이 터 를 통합 시킨다.3. 상기 방식 은 SqlSessionTemplate 조회 만 지원 하지만, 이러한 조 회 는 반드시 mapper 가 있 는 sqlId 에 대응 해 야 합 니 다.사용자 정의 sql 을 사용 하여 조회 할 필요 가 있 으 면 대부분 jdbcTemplate 를 사용 합 니 다. 그러나 이때 jdbcTemplate 에서 사용 하 는 dataSource 는 동적 데이터 원본 이 아니 기 때문에 jdbcTemplate 를 사용 하면 데이터 원본 을 전환 하 는 효 과 를 낼 수 없습니다.이 를 위해 mybatis 의 가장 간단 한 사용자 정의 SQL 문장 을 참고 할 수 있 습 니 다. 원 리 는 마 퍼 를 새로 만 드 는 것 입 니 다.
List select(String sql);



parameterType 이 String 이면 매개 변수 이름 을 써 야 합 니 다parameter, \ # {sqlStr} 을 사용 할 수 없습니다. 그렇지 않 으 면 sql 주입 오류 가 발생 할 수 있 습 니 다.
참고 자료 제8 장 springboot + mybatis + 다 중 데이터 원본 Spring Boot Druid 데이터 원본 설정

좋은 웹페이지 즐겨찾기