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;
}
}
其中JdbcMapper和OracleJdbcMapper是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都需要按照命名指定正確。注意這幾點,配置起來就會簡單許多了。