zoukankan      html  css  js  c++  java
  • Mybatis Spring multiple databases Java configuration

    https://stackoverflow.com/questions/18201075/mybatis-spring-multiple-databases-java-configuration

    ********************************************************************

    I'm working with Spring and Mybatis and I have two databases, the configuration for the first database was relative easy, but I can't get to work the second database with Spring and transactions, here is my code

    @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());
    }
    }

    Is there a way to get this working with pure Spring Java configuration or at least with some XML? There's no official documentation to get two databases working in the Mybatis-Spring project

    Multi datasources with mybatis are used in my project right now. This is an Example, add to your 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"/>

    Add answer with java config example we use in our project:

    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;
        }
    }

    In my experience, you should also add @Primary to one of the DataSource beans. Otherwise it will throw NoUniqueBeanDefinitionException.

    @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);
    }

    You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey().

    Spring Configuration

    You can define separate datasource in spring configuration.

    <!-- 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>

    Associate the datasource with customer:

    <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>

    Java

    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();
     }
    }

    Basically, each request will have its context. You can associate datasource with request using mapped key. You can find more details here dynamic-datasource-routing

    **************

    <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>

    As mentioned above, we need to give corresponding sessionFactory in your DaoImpl. You can not autowire SqlSessionTemplate
    in your DaoImpl class if you have more than one sessionFactory. Give unique name for each session factory and map it to your respective DaoImpl class.
    All you have to do is just to create object for SqlSessionTemplate with Setter method in DaoImpl class and you can make your db call using sqlSessionTemplate object as below,
    this.sqlSessionTemplate.selectList("ProcedureID", parameter);


  • 相关阅读:
    [ ERROR ] Error in test library 'pymysql': Creating keyword 'Connect' failed: Keyword with same name defined multiple times.
    【robotframework】pycharm+robotframe(转)
    Django 配置mysql遇到问题(一)
    Django 初始化数据库遇到问题(python manage.py migrate)
    连接mysql报"ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to connect to this MySQL server"
    性能测试-MySQL性能查看(转)
    APP安全测试
    在线java堆栈分析工具
    性能-如何根据线程和进程找到性能瓶颈或者问题点
    Jmeter CSV参数带汉字处理
  • 原文地址:https://www.cnblogs.com/zhao1949/p/7124433.html
Copyright © 2011-2022 走看看