公司做项目,稍微大一点的项目可能会存在数据源来源不同问题,这里说的数据源来源指的是数据库源,比如一个项目既要从mysql数据库中取数据,又要从Oracle中取数据,或者从mysql数据库下的两个数据库中取数据比如test01,test02数据库,此时该如何处理,正常情况我们都只是一个数据源来源,所以配置一个默认的即可,而两个数据来源的话可能就要从数据库的DataSource类入手了,目前我使用的都是springboot项目,所以下面将的都是在springboot环境下作的操作,如果不理解springboot的可以先去学习一下。整篇文章参考:https://www.cnblogs.com/java-zhao/p/5413845.html 但做了很多修改为了能让读者读懂,这里我暂且认为是我的原创文章。
多数据源也就是配置多个DataSource类型,比如你有两个数据源来源,可以定义type:test01,test02(一般和数据库名相同),项目在使用数据库的时候需要提前将你要使用哪种类型的DataSource告知给系统(这个系统指的是采用的数据库查询框架),系统获取到类型,选择使用哪个DataSource。这里的问题在于:1、如何告知系统我此时需要这个数据源,而不是其他的数据源。2、假如系统已经知道我要使用哪种数据源了,此时系统需要从一个数据源集合中取出该数据源使用,但系统的这个数据源集合我怎么给系统,让系统知道我就是用这些数据源。这两个问题解决了也就基本完事了,下面就来分析解决一下。
1、如何告知系统我此时需要这个数据源,而不是其他的数据源,先来分析一下获取DataSource的源码,这个是AbstractRoutingDataSource类里面的方法,看下面
相信读者已经看明白了此时我们要继承AbstractRoutingDataSource,实现determineCurrentLookupKey这个方法,将DataSource的类型传过去。下面是自定义代码:
package com.more.datasource.more_datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源(需要继承AbstractRoutingDataSource)
* 在使用查询数据库前需要先设置 dataSourceType;
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static String dataSourceType;
/**
* 返回数据源类型,让系统知道我用的是哪个数据源
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return dataSourceType;
}
/**
* 设置数据源类型,在使用数据库之前自己调用该方法
* @param type
*/
public static void setDataSourceType(String type){
dataSourceType = type;
}
}
数据源类型我们这里单独定义一个常量类,存储数据源类型:
package com.more.datasource.more_datasource;
/**
* 此类存储是不同数据库来源对应的type ,例:datashare数据库对应type为DATA_SHARE;
*/
public interface DatasourceType {
/**
* 数据库为datashare 的type
*/
public static String DATA_SHARE = "datashare";
/**
* 数据库为test 的type
*/
public static String TEST = "test";
}
2、系统到此时已经知道我们想要什么数据源了,这时系统要从数据源集合中利用type取出数据源(上面源码已经有标识),现在解决给系统设置数据源集合。看一下源码,还是AbstractRoutingDataSource类的
//设置数据源集合类,参数是map集合,key就是我们定义的数据源类型,value就是数据源
public void setTargetDataSources(Map
此时问题已基本解决,下面贴一下代码
2.1 数据源配置文件配置 application.properties:
#the first datasource
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.100.3:3306/datashare?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=admin
#the second datasource
jdbc2.driverClassName=com.mysql.jdbc.Driver
jdbc2.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc2.username=root
jdbc2.password=root
2.2 自定义config类,让springboot启动加载时提前将数据源等配置加载到系统中
package com.more.datasource.more_datasource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
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.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@Configuration // 该注解类似于spring配置文件
public class MyBatisConfig {
@Autowired
private Environment env;
/**
* 创建数据源(数据源的名称:方法名可以取为XXXDataSource(),XXX为数据库名称,该名称也就是数据源的名称)
*/
@Bean
public DataSource myTestDbDataSource() throws Exception {
Properties props = new Properties();
props.put("driverClassName", env.getProperty("jdbc.driverClassName"));
props.put("url", env.getProperty("jdbc.url"));
props.put("username", env.getProperty("jdbc.username"));
props.put("password", env.getProperty("jdbc.password"));
return DruidDataSourceFactory.createDataSource(props);
}
@Bean
public DataSource myTestDb2DataSource() throws Exception {
Properties props = new Properties();
props.put("driverClassName", env.getProperty("jdbc2.driverClassName"));
props.put("url", env.getProperty("jdbc2.url"));
props.put("username", env.getProperty("jdbc2.username"));
props.put("password", env.getProperty("jdbc2.password"));
return DruidDataSourceFactory.createDataSource(props);
}
/**
* @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错
* @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)
*/
@Bean
@Primary
public DynamicDataSource dataSource(@Qualifier("myTestDbDataSource") DataSource myTestDbDataSource,
@Qualifier("myTestDb2DataSource") DataSource myTestDb2DataSource) {
Map
实体类的创建shop实体
package com.more.datasource.more_datasource.model;
import java.io.Serializable;
/**
* @author WYH
*/
public class Shop implements Serializable {
private String id;
private String shopName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
@Override
public String toString() {
return "Shop{" +
"id='" + id + '\'' +
", shopName='" + shopName + '\'' +
'}';
}
}
实体类的创建DxTest实体
package com.more.datasource.more_datasource.model;
import java.io.Serializable;
/**
* @author WYH
*/
public class DxTest implements Serializable {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
mapper接口类创建,这里采用的是注解方式查询数据库,没有使用xml的方式
package com.more.datasource.more_datasource.mapper;
import com.more.datasource.more_datasource.model.DxTest;
import com.more.datasource.more_datasource.model.Shop;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@Mapper
@Repository("mapper")
public interface ShopMapper {
@Select("SELECT * FROM student WHERE id = #{id}")
@Results(value = { @Result(id = true, column = "id", property = "id"),
@Result(column = "name", property = "shopName") })
public Shop getShop(@Param("id") int id);
@Select("SELECT * FROM t_data_field WHERE id = #{id}")
@Results(value = { @Result(id = true, column = "id", property = "id"),
@Result(column = "tablename", property = "name") })
public DxTest getDxTest(@Param("id") int id);
}
controller类的创建,这里将service,dao两层给去掉,简化了一下步骤,方便阅读
package com.more.datasource.more_datasource.controller;
import com.more.datasource.more_datasource.DatasourceType;
import com.more.datasource.more_datasource.DynamicDataSource;
import com.more.datasource.more_datasource.mapper.ShopMapper;
import com.more.datasource.more_datasource.model.DxTest;
import com.more.datasource.more_datasource.model.Shop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/shop")
public class ShopController {
@Autowired
private ShopMapper mapper;
@RequestMapping(value = "/getShop", method = RequestMethod.GET)
public Shop getShop() {
//查询数据前设置数据源类型
DynamicDataSource.setDataSourceType(DatasourceType.TEST);
return mapper.getShop(1);
}
@RequestMapping(value = "/getDxTest", method = RequestMethod.GET)
public DxTest getDxTest(){
//查询数据前设置数据源类型
DynamicDataSource.setDataSourceType(DatasourceType.DATA_SHARE);
return mapper.getDxTest(3238);
}
}
到此,多数据源已经实现完毕,此案例也留着自己以后快速设计多数据源结构做准备。