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


  • 相关阅读:
    weblogic一些基本概念
    网络通信框架Apache MINA
    SpringMVC利用Hibernate validator做字段验证
    jQuery.extend 函数详解
    Spring测试
    java的string.split()分割特殊字符时注意点
    SpringMVC集成shrio框架
    使用SpringMVC时,配置DispatcherServlet注意的url-pattern的问题
    jsp页面中EL表达式不能被解析
    SpringMVC的视图解析器
  • 原文地址:https://www.cnblogs.com/zhao1949/p/7124433.html
Copyright © 2011-2022 走看看