1. 程式人生 > >springboot+Mybatis配置實現多資料來源

springboot+Mybatis配置實現多資料來源

簡述

應公司需求,結合網上的許多資料和公司專案配置實現多資料來源。在此記錄一下配置過程,以供大家參考。

專案簡介

框架用的是SpringBoot+Mybatis,初始資料庫是MySQL,具體MySQL的整合在這裡不做詳細說明,要求是新增一個Oracle的資料來源,實現可以同時查詢MySQL和Oracle兩個資料庫的功能。專案所用資料來源是阿里的Druid,沒有用傳統的配置檔案,用的是disconf進行的配置管理。

配置資料庫

pom檔案就不寫了,比較簡單,Oracle的包新增下就可以了。主要是資料庫這邊的配置,我將MySQL和Oracle的資料庫配置寫在了一起。

package
com.server.configs; import com.alibaba.druid.filter.Filter; import com.alibaba.druid.filter.stat.StatFilter; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.wall.WallConfig; import com.alibaba.druid.wall.WallFilter; import com.core.mapper.JdbcMapper; import com.core.mapper.OracleJdbcMapper; import
org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import javax.sql.DataSource; import
java.util.ArrayList; import java.util.List; /** * Created by jht on 2017-5-25. */ @SuppressWarnings("ALL") @Configuration public class DatabaseConfig { @Autowired private JdbcMapper jdbcMapper; @Autowired private OracleJdbcMapper oracleJdbcMapper; @Primary @Bean(name = "mysqlDataSource") public DataSource dataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setDriverClassName(jdbcMapper.getDriverClassName()); datasource.setUrl(jdbcMapper.getUrl()); datasource.setUsername(jdbcMapper.getUsername()); datasource.setPassword(jdbcMapper.getPassword()); datasource.setInitialSize(jdbcMapper.getInitialSize()); datasource.setMaxActive(jdbcMapper.getMaxActive()); datasource.setMaxWait(jdbcMapper.getMaxWait()); datasource.setMinIdle(jdbcMapper.getMinIdle()); datasource.setTimeBetweenEvictionRunsMillis(jdbcMapper.getTimeBetweenEvictionRunsMillis()); datasource.setMinEvictableIdleTimeMillis(jdbcMapper.getMinEvictableIdleTimeMillis()); datasource.setValidationQuery(jdbcMapper.getValidationQuery()); datasource.setTestWhileIdle(jdbcMapper.getTestWhileIdle()); datasource.setTestOnBorrow(jdbcMapper.getTestOnBorrow()); datasource.setTestOnReturn(jdbcMapper.getTestOnReturn()); datasource.setMaxOpenPreparedStatements(jdbcMapper.getMaxOpenPreparedStatements()); datasource.setRemoveAbandoned(jdbcMapper.getRemoveAbandoned()); datasource.setRemoveAbandonedTimeout(jdbcMapper.getRemoveAbandonedTimeout()); datasource.setLogAbandoned(jdbcMapper.getLogAbandoned()); List<Filter> list = new ArrayList(); list.add(new StatFilter()); WallFilter wallFilter = new WallFilter(); WallConfig config = new WallConfig(); config.setMultiStatementAllow(true); wallFilter.setConfig(config); list.add(wallFilter); datasource.setProxyFilters(list); return datasource; } @Bean(name = "oracleDataSource") public DataSource oracleDataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setDriverClassName(oracleJdbcMapper.getDriverClassName()); datasource.setUrl(oracleJdbcMapper.getUrl()); datasource.setUsername(oracleJdbcMapper.getUsername()); datasource.setPassword(oracleJdbcMapper.getPassword()); datasource.setInitialSize(oracleJdbcMapper.getInitialSize()); datasource.setMaxActive(oracleJdbcMapper.getMaxActive()); datasource.setMaxWait(oracleJdbcMapper.getMaxWait()); datasource.setMinIdle(oracleJdbcMapper.getMinIdle()); datasource.setTimeBetweenEvictionRunsMillis(oracleJdbcMapper.getTimeBetweenEvictionRunsMillis()); datasource.setMinEvictableIdleTimeMillis(oracleJdbcMapper.getMinEvictableIdleTimeMillis()); datasource.setValidationQuery(oracleJdbcMapper.getValidationQuery()); datasource.setTestWhileIdle(oracleJdbcMapper.getTestWhileIdle()); datasource.setTestOnBorrow(oracleJdbcMapper.getTestOnBorrow()); datasource.setTestOnReturn(oracleJdbcMapper.getTestOnReturn()); datasource.setMaxOpenPreparedStatements(oracleJdbcMapper.getMaxOpenPreparedStatements()); datasource.setRemoveAbandoned(oracleJdbcMapper.getRemoveAbandoned()); datasource.setRemoveAbandonedTimeout(oracleJdbcMapper.getRemoveAbandonedTimeout()); datasource.setLogAbandoned(oracleJdbcMapper.getLogAbandoned()); List<Filter> list = new ArrayList(); list.add(new StatFilter()); WallFilter wallFilter = new WallFilter(); WallConfig config = new WallConfig(); config.setMultiStatementAllow(true); wallFilter.setConfig(config); list.add(wallFilter); datasource.setProxyFilters(list); return datasource; } }

其中JdbcMapperOracleJdbcMapper是disconf配置檔案對應的配置類。
@Primary 用來指定一個主資料來源,這裡是將MySQL的資料庫設為主資料來源。

配置資料來源

多新增一個Oracle庫,mapper包和xml包還有PO都跟MySQL的分開,所以寫了兩套mybatis配置資料來源的配置類。先貼上主資料庫MySQL的配置類。

package com.server.configs;

import com.github.pagehelper.PageHelper;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mapstruct.Mapper;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

/**
 * Created by jht on 2017/5/30.
 */
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.server.dao.mapper", sqlSessionTemplateRef = "mysqlSessionTemplate")
public class MyBatisConfig {

    @Resource
    DataSource mysqlDataSource;

    @Primary
    @Bean(name = "mysqlSessionFactory")
    public SqlSessionFactory mysqlSessionFactory() throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(mysqlDataSource);
        sessionFactory.setTypeAliasesPackage("com.ydx.server.model.mysql");
        //分頁外掛
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);

        //新增外掛
        sessionFactory.setPlugins(new Interceptor[]{pageHelper});

        //新增XML目錄
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            sessionFactory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
            return sessionFactory.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Primary
    @Bean(name = "mysqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mysqlSessionFactory") SqlSessionFactory mysqlSessionFactory) {
        return new SqlSessionTemplate(mysqlSessionFactory);
    }

    @Primary
    @Bean(name = "mysqlTransactionManager")
    public PlatformTransactionManager mysqlTransactionManager() {
        return new DataSourceTransactionManager(mysqlDataSource);
    }

}

需要注意的是因為是主資料庫,所以需要加@Primary;
@Bean的名字要需要寫清楚;
@MapperScan的包名要寫對;

下面是Oracle的配置類,差別不大。

package com.server.configs;

import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * Created by jht on 2017/5/30.
 */
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.server.dao.oracle", sqlSessionTemplateRef = "oracleSessionTemplate")
public class OracleMyBatisConfig {

    @Resource
    DataSource oracleDataSource;

    @Bean(name = "oracleSessionFactory")
    public SqlSessionFactory mysqlSessionFactory() throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(oracleDataSource);
        sessionFactory.setTypeAliasesPackage("com.ydx.server.model.mysql");
        //分頁外掛
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);

        //新增外掛
        sessionFactory.setPlugins(new Interceptor[]{pageHelper});

        //新增XML目錄
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            sessionFactory.setMapperLocations(resolver.getResources("classpath:oraclemapper/*.xml"));
            return sessionFactory.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean(name = "oracleSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("oracleSessionFactory") SqlSessionFactory oracleSessionFactory) {
        return new SqlSessionTemplate(oracleSessionFactory);
    }

    @Bean(name = "oracleTransactionManager")
    public PlatformTransactionManager oracleTransactionManager() {
        return new DataSourceTransactionManager(oracleDataSource);
    }

}

跟MySQL的配置差不多,到此為止,多資料來源配置就算完成啦。接下來的測試我就不貼了。

總結

其實還有一種方式是動態配置資料來源的,用到了AOP,有時間在研究吧。這個方式比較死板,維護起來比較麻煩,適合那種只是想找一個簡單的多資料來源支援的專案。最重要的其實就是一步步的注入,先建立DataSource,然後通過注入DataSource建立SessionFactory,再建立事務,最後包裝到SqlSessionTemplate中。其中DAO包,PO類,xml所在位置都需要準確指定。所有@Bean都需要按照命名指定正確。注意這幾點,配置起來就會簡單許多了。