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


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

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

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

DatabaseType

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

這里就是列出所有的數據源,相當於定義了兩個常量,便於統一維護

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包下面的類

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類型的實例,需要指定名稱裝配。

還有數據源配置文件

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

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

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了。剩下的業務代碼很簡單就不貼了。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM