简体   繁体   English

Mybatis Spring多个数据库Java配置

[英]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 我正在使用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());
}
}

Is there a way to get this working with pure Spring Java configuration or at least with some XML? 有没有办法让这个使用纯Spring Java配置或至少使用一些XML? There's no official documentation to get two databases working in the Mybatis-Spring project 没有官方文档可以让两个数据库在Mybatis-Spring项目中运行

Multi datasources with mybatis are used in my project right now. 我的项目现在使用带有mybatis的多数据源。 This is an Example, add to your application.xml 这是一个示例,添加到您的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>

Add answer with java config example we use in our project: 使用我们在项目中使用的java配置示例添加答案:

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. 根据我的经验,您还应该将@Primary添加到其中一个DataSource bean中。 Otherwise it will throw NoUniqueBeanDefinitionException . 否则它将抛出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() . 您可以通过扩展它并覆盖方法determineCurrentLookupKey()来使用spring的AbstractRoutingDataSource

Spring Configuration 弹簧配置

You can define separate datasource in spring configuration. 您可以在spring配置中定义单独的datasource

<!-- 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 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. 您可以使用映射密钥将datasource与请求相关联。 You can find more details here dynamic-datasource-routing 您可以在此处找到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. 如上所述,我们需要在DaoImpl中给出相应的sessionFactory。 You can not autowire SqlSessionTemplate in your DaoImpl class if you have more than one sessionFactory. 如果您有多个sessionFactory,则无法在DaoImpl类中自动装配SqlSessionTemplate。 Give unique name for each session factory and map it to your respective DaoImpl class. 为每个会话工厂指定唯一名称,并将其映射到相应的DaoImpl类。 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); 您所要做的就是在DaoImpl类中使用Setter方法为SqlSessionTemplate创建对象,您可以使用sqlSessionTemplate对象进行db调用,如下所示:this.sqlSessionTemplate.selectList(“ProcedureID”,参数);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM