복붙노트

[SPRING] Mybatis 봄 여러 데이터베이스 Java 구성

SPRING

Mybatis 봄 여러 데이터베이스 Java 구성

Spring과 Mybatis로 작업하고 있는데 두 개의 데이터베이스가 있습니다. 첫 번째 데이터베이스의 구성은 상대적으로 쉽지만 Spring과 트랜잭션을 사용하여 두 번째 데이터베이스를 처리 할 수는 없습니다. 여기에 제 코드가 있습니다.

@Configuration
@ComponentScan(basePackages = {"hernandez.service", "hernandez.dao"})
@EnableTransactionManagement
@MapperScan(basePackages="hernandez.mapper" ) 
@Import(DbConfig2.class)
public class AppConfig {

@Bean(name = "dataSource")
public DataSource dataSource() {
    DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
            "jdbc:mysql://localhost:3306/northwind", "root", "");
    return ds;
}

@Bean
public SqlSessionFactoryBean sqlSessionFactory() {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource()); 
    return factoryBean;
}

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

@Configuration
@MapperScan("loli.mapper" ) 
public class DbConfig2 {
@Bean(name = "dataSource_2")
public DataSource dataSource2() {
    DriverManagerDataSource ds = new DriverManagerDataSource("com.mysql.jdbc.Driver",
            "jdbc:mysql://localhost:3306/dmsolut_dmsms", "root", "");
    return ds;
}

@Bean
public SqlSessionFactory sqlSessionFactory2() throws Exception{
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource2());
    return factoryBean.getObject();
}

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

순수 Spring Java 구성으로 작업하거나 적어도 XML로 작업 할 수있는 방법이 있습니까? Mybatis-Spring 프로젝트에서 두 개의 데이터베이스가 작동하도록하는 공식 문서는 없습니다.

해결법

  1. ==============================

    1.mybatis가있는 다중 데이터 소스가 현재 내 프로젝트에서 사용됩니다. 이 예제는 application.xml에 추가합니다.

    mybatis가있는 다중 데이터 소스가 현재 내 프로젝트에서 사용됩니다. 이 예제는 application.xml에 추가합니다.

      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
        <property name="url" value="${center.connectionURL}"/>
        <property name="username"  value="${userName}"/>
        <property name="password" value="${password}"/>
    </bean>
    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.xxx.dao.center"/>
        <property name="sqlSessionFactoryBeanName" value="cneterSqlSessionFactory"/>
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" name="cneterSqlSessionFactory">
        <property name="dataSource" ref="dataSource"></property>
        <property name="mapperLocations" value="classpath*:mapperConfig/center/*.xml"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!--center db end-->
    <!--exdb-->
    <bean id="dataSourceEx" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
        <property name="url" value="${ex.connectionURL}"/>
        <property name="username"  value="${userName}"/>
        <property name="password" value="${password}"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.xxx.dao.ex"/>
        <property name="sqlSessionFactoryBeanName" value="exSqlSessionFactory"/>
    </bean>
    <bean id="sqlSessionFactoryEx" class="org.mybatis.spring.SqlSessionFactoryBean" name="exSqlSessionFactory">
        <property name="dataSource" ref="dataSourceEx"></property>
        <property name="mapperLocations" value="classpath*:mapperConfig/ex/*.xml"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <bean id="transactionManagerEx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSourceEx"/>
    </bean>
    
  2. ==============================

    2.프로젝트에서 사용하는 java config 예제를 사용하여 답변 추가 :

    프로젝트에서 사용하는 java config 예제를 사용하여 답변 추가 :

    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.type.JdbcType;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.mapper.MapperScannerConfigurer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    
    @Configuration
    @ComponentScan(basePackages = "com.mycompany")
    @EnableTransactionManagement(proxyTargetClass = true)
    public class ApplicationConfig2 {
        public static final String DATA_SOURCE_NAME_1 = "jdbc/dataSource1";
        public static final String DATA_SOURCE_NAME_2 = "jdbc/dataSource2";
    
        public static final String SQL_SESSION_FACTORY_NAME_1 = "sqlSessionFactory1";
        public static final String SQL_SESSION_FACTORY_NAME_2 = "sqlSessionFactory2";
    
        public static final String MAPPERS_PACKAGE_NAME_1 = "com.mycompany.mappers.dao1";
        public static final String MAPPERS_PACKAGE_NAME_2 = "com.mycompany.mappers.dao2";
    
        @Bean
        public DataSource dataSource1() {
            JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
            return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
        }
    
        @Bean
        public DataSource dataSource2() {
            JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
            return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
        }
    
        @Bean
        public PlatformTransactionManager transactionManager() {
            return new DataSourceTransactionManager(dataSource());
        }
    
    
        @Bean(name = SQL_SESSION_FACTORY_NAME_1)
        public SqlSessionFactory sqlSessionFactory1(DataSource dataSource1) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
            sqlSessionFactoryBean.setDataSource(dataSource1);
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
            sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
            sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
            return sqlSessionFactory;
        }
    
        @Bean(name = SQL_SESSION_FACTORY_NAME_2)
        public SqlSessionFactory sqlSessionFactory2(DataSource dataSource2) throws Exception {
            SqlSessionFactoryBean diSqlSessionFactoryBean = new SqlSessionFactoryBean();
            diSqlSessionFactoryBean.setTypeHandlersPackage(DateTimeTypeHandler.class.getPackage().getName());
            diSqlSessionFactoryBean.setDataSource(dataSource2);
            SqlSessionFactory sqlSessionFactory = diSqlSessionFactoryBean.getObject();
            sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);
            sqlSessionFactory.getConfiguration().setJdbcTypeForNull(JdbcType.NULL);
            return sqlSessionFactory;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer1() {
            MapperScannerConfigurer configurer = new MapperScannerConfigurer();
            configurer.setBasePackage(MAPPERS_PACKAGE_NAME_1);
            configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_1);
            return configurer;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer2() {
            MapperScannerConfigurer configurer = new MapperScannerConfigurer();
            configurer.setBasePackage(MAPPERS_PACKAGE_NAME_2);
            configurer.setSqlSessionFactoryBeanName(SQL_SESSION_FACTORY_NAME_2);
            return configurer;
        }
    }
    
  3. ==============================

    3.내 경험에 비추어 볼 때, DataSource Bean 중 하나에 @Primary도 추가해야한다. 그렇지 않은 경우, NoUniqueBeanDefinitionException가 throw됩니다.

    내 경험에 비추어 볼 때, DataSource Bean 중 하나에 @Primary도 추가해야한다. 그렇지 않은 경우, NoUniqueBeanDefinitionException가 throw됩니다.

    @Bean
    @Primary
    public DataSource dataSource1() {
        JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        return dsLookup.getDataSource(DATA_SOURCE_NAME_1);
    }
    
    @Bean
    public DataSource dataSource2() {
        JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        return dsLookup.getDataSource(DATA_SOURCE_NAME_2);
    }
    
  4. ==============================

    4.스프링의 AbstractRoutingDataSource를 확장하고 decideCurrentLookupKey () 메서드를 재정 의하여 사용할 수 있습니다.

    스프링의 AbstractRoutingDataSource를 확장하고 decideCurrentLookupKey () 메서드를 재정 의하여 사용할 수 있습니다.

    스프링 구성

    스프링 구성에서 별도의 데이터 소스를 정의 할 수 있습니다.

    <!-- db2 data source -->
    <bean id="db2DataSource" class="com.ibm.db2.jdbc.app.DB2Driver">
      <property name="serverName" value="${db2.jdbc.serverName}" />
      <property name="portNumber" value="${db2.jdbc.portNumber}" />
      <property name="user" value="${db2.jdbc.username}" />
      <property name="password" value="${db2.jdbc.password}" />
      <property name="databaseName" value="${db2.jdbc.databaseName}" />
    </bean>
    
    <!-- mysql data source -->
    <bean id="mysqlDataSource" class="com.mysql.jdbc.Driver">
      <property name="serverName" value="${mysql.jdbc.serverName}" />
      <property name="portNumber" value="${mysql.jdbc.portNumber}" />
      <property name="user" value="${mysql.jdbc.username}" />
      <property name="password" value="${mysql.jdbc.password}" />
      <property name="databaseName" value="${mysql.jdbc.databaseName}" />
    </bean>
    

    데이터 소스를 고객과 연결 :

    <bean id="customer" class="com.example.Customer">
      <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean id="dataSource" class="com.example.datasource.CustomerRoutingDataSource">
      <property name="targetDataSources">
      <map key-type="com.example.Customer">
         <entry key="db2" value-ref="mysqlDataSource"/>
         <entry key="mysql" value-ref="db2DataSource"/>
      </map>
      </property>
      <property name="defaultTargetDataSource" ref="mysql"/>
    </bean>
    

    자바

    package com.example;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
    
     @Bean
     CustomerContextHolder context;
    
     @Override
     protected Object determineCurrentLookupKey() {
      return context.getCustomerType();
     }
    }
    

    기본적으로 각 요청에는 해당 컨텍스트가 있습니다. 매핑 된 키를 사용하여 요청과 데이터 소스를 연결할 수 있습니다. 자세한 내용은 여기에서 확인할 수 있습니다. dynamic-datasource-routing

  5. ==============================

    5.

    <bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource1" />
        <property name="configLocation">
            <value>classpath:com/dtcc/dao/impl/DaoSqlMapConfig_MyBatis1.xml</value>
      </property>
       <property name="transactionFactory">
            <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
        </property>  
        <property name="mapperLocations" value="classpath*:com/dtcc/dao/impl/DaoEmfMyBatis.sp.xml"/> 
    </bean>
    <bean id="sqlSession1" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory1" />
    </bean> 
    <!-- MyBatis Changes Ends -->
    
    <bean id="daoEmf" class="com.dtcc.dao.DaoEmfImpl">
        <property name="connectionType"><ref local="com.dtcc.sharedservices.utils.resources.ConnTypes.IBM_DB2_CONNECTION" /></property>
        <property name="jndiNameForLogging"><ref local="dataSourceName1" /></property>
        <property name="sqlSessionTemplate"> <ref local="sqlSession1" /></property>
        <property name="applicationLog"><ref local="appLog" /></property>
    </bean>
    

    앞서 언급했듯이 DaoImpl에 상응하는 sessionFactory를 제공해야합니다. 둘 이상의 sessionFactory가있는 경우 DaoImpl 클래스에서 SqlSessionTemplate을 자동으로 호출 할 수 없습니다. 각 세션 팩토리에 대해 고유 한 이름을 지정하고 해당 DaoImpl 클래스에 매핑하십시오. DaoImpl 클래스에서 Setter 메소드를 사용하여 SqlSessionTemplate에 대한 객체를 생성하면 아래와 같이 sqlSessionTemplate 객체를 사용하여 db 호출을 할 수 있습니다. this.sqlSessionTemplate.selectList ( "ProcedureID", 매개 변수);

  6. from https://stackoverflow.com/questions/18201075/mybatis-spring-multiple-databases-java-configuration by cc-by-sa and MIT license