springboot整合mybatis的多數據源解決辦法

  最近項目有一個非解決不可的問題,咱們的項目中的用戶表是用的本身庫的數據,可是這些數據都是從一個已有庫中遷過來的,因此用戶信息都是在那個項目裏面維護,天然而然咱們項目不提供用戶註冊功能,這就有個問題,如何解決數據遷移的問題,總不能我每次都手動導數據吧,因此我決心寫一個接口把那個庫中的用戶信息同步咱們的庫中去。java

  這又涉及到一個問題,如何在一個服務中鏈接兩個庫,在網上搜索了一番,算是把問題解決了,現將多數據源demo代碼貼出來,先看一下個人目錄結構mysql

controller、mapper、pojo、service這幾個常見的業務邏輯包咱們放到最後看,先看一下util包裏面的類spring

DatabaseType

/**
 * 採用枚舉的方法列出全部的數據源key(經常使用數據庫名稱來命名)
 * 數據源個數和數據庫個數保持一致
 */
public enum DatabaseType {
    mytestdb,mytestdb2
}

這裏就是列出全部的數據源,至關於定義了兩個常量,便於統一維護sql

DynamicDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
 * 動態數據源(須要繼承AbstractRoutingDataSource)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    //定義一個線程安全的DatabaseType容器
    private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<DatabaseType>();

    public static DatabaseType getDatabaseType(){
        return contextHolder.get();
    }

    public static void setDatabaseType(DatabaseType type) {
        contextHolder.set(type);
    }
    //獲取當前線程的DatabaseType
    protected Object determineCurrentLookupKey() {
      return getDatabaseType();
  }
}

在這裏建立一個動態數據源的類,定義了DatabaseType的get和set方法,用getDatabaseType()得到一個當前線程的DatabaseType來重寫determineCurrentLookupKey()方法。數據庫

最後來看一下config包下面的類apache

MybatisConfig

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;


import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.fiberhome.ms.multiDataSource.util.DatabaseType;
import com.fiberhome.ms.multiDataSource.util.DynamicDataSource;

/**
 * springboot集成mybatis的基本入口 
 * 1) 獲取數據源
 * 2)建立數據源
 * 3)建立SqlSessionFactory 
 * 4)配置事務管理器,除非須要使用事務,不然不用配置
 */
@Configuration 
public class MybatisConfig implements EnvironmentAware {

    private Environment environment;

    public void setEnvironment(final Environment environment) {
        this.environment = environment;
    }

    /**
     * 建立數據源,從配置文件中獲取數據源信息
     */
    @Bean
    public DataSource testDataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty("jdbc.driverClassName"));
        props.put("url", environment.getProperty("jdbc.url"));
        props.put("username", environment.getProperty("jdbc.username"));
        props.put("password", environment.getProperty("jdbc.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    @Bean
    public DataSource test1DataSource() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty("jdbc2.driverClassName"));
        props.put("url", environment.getProperty("jdbc2.url"));
        props.put("username", environment.getProperty("jdbc2.username"));
        props.put("password", environment.getProperty("jdbc2.password"));
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**注入數據源
     */
    @Bean
    public DynamicDataSource dataSource(@Qualifier("testDataSource")DataSource testDataSource, @Qualifier("test1DataSource")DataSource test1DataSource) {
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        targetDataSources.put(DatabaseType.mytestdb, testDataSource);
        targetDataSources.put(DatabaseType.mytestdb2, test1DataSource);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 該方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(testDataSource);// 默認的datasource設置爲myTestDbDataSource

        return dataSource;
    }

    /**
     * 根據數據源建立SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("testDataSource") DataSource testDataSource,
                                               @Qualifier("test1DataSource") DataSource test1DataSource) throws Exception{
      PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();  
      SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(this.dataSource(testDataSource, test1DataSource));
        fb.setTypeAliasesPackage("com.fiberhome.ms.multiDataSource");// 指定基包
        fb.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));//
        return fb.getObject();
    }


    /**
     * 配置事務管理器
     */
    @Bean
    public DataSourceTransactionManager testTransactionManager(DynamicDataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }


}

上面這段代碼在建立數據源DataSource實例時採用的是@bean註解注入的方式,使其成爲受spring管理的bean。在後面的方法把兩個DataSource做爲參數傳入,能夠看到用了@Qualifier註解,加這個註解是爲了解決多個實例沒法直接裝配的問題,在這裏有兩個DataSource類型的實例,須要指定名稱裝配。安全

還有數據源配置文件springboot

application.properties

#the first datasource
jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
jdbc.username = root
jdbc.password = 123456

#the second datasource
jdbc2.driverClassName = com.mysql.jdbc.Driver
jdbc2.url = jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8
jdbc2.username = root
jdbc2.password = 123456

說完了關鍵的通用代碼,再來看看如何在業務代碼中使用session

UserServiceImpl

import com.fiberhome.ms.multiDataSource.mapper.UserMapper;
import com.fiberhome.ms.multiDataSource.pojo.User;
import com.fiberhome.ms.multiDataSource.service.UserService;
import com.fiberhome.ms.multiDataSource.util.DatabaseType;
import com.fiberhome.ms.multiDataSource.util.DynamicDataSource;
@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private UserMapper userMapper;

  @Override
  public List<User> getTestUser() {
    //設置數據源
    DynamicDataSource.setDatabaseType(DatabaseType.mytestdb);
    return userMapper.findUser();
  }

  @Override
  public List<User> getTest1User() {
    //設置數據源
    DynamicDataSource.setDatabaseType(DatabaseType.mytestdb2);
    return userMapper.findUser();
  }
 
}

在service層的實現類中設置數據源便可指定哪一個mapper接口使用哪一個數據源,這樣就OK了。剩下的業務代碼很簡單就不貼了。。。mybatis

相關文章
相關標籤/搜索