本文主要思路参考自文章http://blog.csdn.net/maoyeqiu/article/details/74011626,感谢
一、业务需求:
在已经连接了数据库DB1的前提下,需要去另一个库DB2查询数据并展示。
由于实际项目涉及商业秘密,在这里我就参考下网上现有的文章大致写一下要点。
参考文章网址 http://blog.csdn.net/maoyeqiu/article/details/74011626 ,有关细节请读者参考原文
二、技术方案:
结合现有的Spring Boot+MyBatis框架,实现多数据源。常用的有静态方式,动态方式。静态方式相对容易
理解,故本篇先讲。静态方案主要包括以下几点:
两套数据源配置properties文件,两套Mybatis配置类(包括初始化数据源、创建sqlSessionFactory、创建事务管理器),两套Mapper(包括entity类、mapper.java、mapper.xml文件),各自处理各自的业务;
两套数据源都可以进行增删改查的操作,在这两个主MYSQL后也可以各自配置自己的slave,实现数据的备份;
如果再增加一个数据源就得从头到尾的增加一遍。
三、具体实现
3.1、两套数据源配置
#db1
spring.datasource.url=${value.spring.datasource.url}
spring.datasource.username=${value.spring.datasource.username}
spring.datasource.password=${value.spring.datasource.password}
#db2
spring.datasource.db2.url=${value.spring.datasource.db2.url}
spring.datasource.db2.username=${value.spring.datasource.db2.username}
spring.datasource.db2.password=${value.spring.datasource.db2.password}
这两个数据源的配置不分主从,看网上很多这种配置方式,说是主从配置,个人认为既然什么都是两套就没有必要分出主从,分出读写了,根据业务的需求以及数据库服务器的性能进行划分即可。
3.2、两套Mybatis配置类
DB1
@Configuration
@EnableTransactionManagement
@ComponentScan
@MapperScan({"com.test.jy.console.dao"}) // 扫描包下所有子目录
public class MyBatisConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisConfig.class);
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Autowired
private Environment env;
@Bean(name = "dataSource", destroyMethod = "close", initMethod = "init")
@Primary
public DataSource dataSource() {
Properties props = new Properties();
props.put("driverClass", env.getProperty("spring.datasource.driver-class-name"));
props.put("url", env.getProperty("spring.datasource.url"));
props.put("username", env.getProperty("spring.datasource.username"));
props.put("password", env.getProperty("spring.datasource.password"));
try {
DruidDataSource druidDataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(props);
//druidDataSource.setPasswordCallback(passwordCallback);
return druidDataSource;
} catch (Exception e) {
LOGGER.error("加载数据库连接池错误!", e);
}
return null;
}
@Bean(name="sqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, DesensAesUtil desensAesUtil) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// 支持多个classpath路径加载
String[] classPathArray = {"classpath:com/test/jy/console/mybatis/xml/*.xml"};
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = null;
for (int i = 0; i < classPathArray.length; i++) {
if (resources == null) {
resources = resolver.getResources(classPathArray[i]);
} else {
resources = (Resource[]) ArrayUtils.addAll(resources, resolver.getResources(classPathArray[i]));
}
}
sqlSessionFactoryBean.setMapperLocations(resources);
sqlSessionFactoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return sqlSessionFactoryBean.getObject();
}
/**
* 配置事务管理器
*/
@Bean(name = "transactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
}
注意点:
@Primary 标志这个 Bean 如果在多个同类 Bean 候选时,该 Bean 优先被考虑。「多数据源配置的时候注意,必须要有一个主数据源,用 @Primary 标志该 Bean」;
每个bean都加上name属性,用来区分不同数据源
DB2
@Configuration
@EnableTransactionManagement
@ComponentScan
@MapperScan(basePackages ="com.test.jy.console.db2dao",sqlSessionFactoryRef ="db2SqlSessionFactory" ) // 扫描包下所有子目录
public class MyBatisConfigForDB2 {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisConfigForDB2.class);
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Autowired
private Environment env;
@Bean(name = "db2DataSource", destroyMethod = "close", initMethod = "init")
public DataSource db2DataSource() {
Properties props = new Properties();
props.put("driverClass", env.getProperty("spring.datasource.driver-class-name"));
props.put("url", env.getProperty("spring.datasource.db2.url"));
props.put("username", env.getProperty("spring.datasource.db2.username"));
props.put("password", env.getProperty("spring.datasource.db2.password"));
try {
DruidDataSource druidDataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(props);
return druidDataSource;
} catch (Exception e) {
LOGGER.error("加载数据库连接池错误!", e);
}
return null;
}
@Bean(name = "db2SqlSessionFactory")
public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource")DataSource dataSource, DesensAesUtil desensAesUtil) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// 支持多个classpath路径加载
String[] classPathArray = {"classpath:com/test/jy/console/mybatis/xml/*.xml"};
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = null;
for (int i = 0; i < classPathArray.length; i++) {
if (resources == null) {
resources = resolver.getResources(classPathArray[i]);
} else {
resources = (Resource[]) ArrayUtils.addAll(resources, resolver.getResources(classPathArray[i]));
}
}
sqlSessionFactoryBean.setMapperLocations(resources);
sqlSessionFactoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
return sqlSessionFactoryBean.getObject();
}
/**
* 配置事务管理器
*/
@Bean(name = "db2TransactionManager")
public DataSourceTransactionManager db2TransactionManager(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
}
3.3、两套Mapper 略
小结:上述步骤注意细节不要搞错,如有错误,在项目启动时就会报错了。
上述步骤就是用静态方法实现同一个项目使用多个数据配置,缺点是不易维护和扩展。