springboot中怎么实现动态数据源,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
/**
* 作用:保存一个线程安全的DatabaseType容器
*/
public class DatabaseContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
/**
* 当需要操作数据库前,也就是调用mapper.c/r/u/d方法前,可以调用该方法
* 该方法的作用是设置需要连接的数据库
* 由于是线程安全,如果一个新的controller连接请求,在操作数据库前没有显式的调用该方法,则get到的databaseType将会为null
* 但这并不影响数据库的操作,因为在数据源的设置中已经设置了默认的数据源
* 当在同一个线程中(也就是本系统controller的同一个请求处理中),如果该方法被调用过
* 则后面的数据库操作,也就是mapper.c/r/u/d的时,get到的都是set好的数据源,除非再次显式的调用这个set方法改变数据源
*/
public static void setDatabaseType(String type) {
contextHolder.set(type);
}
/**
* 当通过mapper.c/r/u/d方法等操作数据库时
* 该方法会自动被determineCurrentLookupKey方法调用到
* determineCurrentLookupKey是重写了Spring里的AbstractRoutingDataSource类的determineCurrentLookupKey方法
*
* @see DynamicDataSource
*/
public static String getDatabaseType() {
return contextHolder.get();
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
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 javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据源工具类
*/
@Configuration
@Slf4j
public class DataSourceUtil {
@Autowired
private Environment env;
//默认数据源
private DataSource defaultDataSource;
//用户自定义数据源
private Map<String, DataSource> slaveDataSources = new HashMap<>();
/**
* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
*/
@Bean
@Primary
public DynamicDataSource dataSource() throws Exception {
initDefaultDataSource();
initSlaveDataSources();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("", defaultDataSource);
targetDataSources.putAll(slaveDataSources);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setDefaultTargetDataSource(defaultDataSource);// 该方法是AbstractRoutingDataSource的方法,默认数据源
dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法,数据源map
return dataSource;
}
private void initDefaultDataSource() {
// 读取主数据源
Map<String, String> dsMap = new HashMap<>();
dsMap.put("driver", env.getProperty("spring.datasource.driver"));
dsMap.put("url", env.getProperty("spring.datasource.url"));
dsMap.put("username", env.getProperty("spring.datasource.username"));
dsMap.put("password", env.getProperty("spring.datasource.password"));
defaultDataSource = buildDataSource(dsMap);
}
private void initSlaveDataSources() {
// 读取配置文件获取更多数据源
String dsPrefixs = env.getProperty("slave.datasource.names");
for (String dsPrefix : dsPrefixs.split(",")) {
// 多个数据源
Map<String, String> dsMap = new HashMap<>();
dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver"));
dsMap.put("url", env.getProperty("slave.datasource." + dsPrefix + ".url"));
dsMap.put("username", env.getProperty("slave.datasource." + dsPrefix + ".username"));
dsMap.put("password", env.getProperty("slave.datasource." + dsPrefix + ".password"));
DataSource ds = buildDataSource(dsMap);
slaveDataSources.put(dsPrefix, ds);
}
}
//指定默认数据源(springboot2.0默认数据源是hikari如何想使用其他数据源可以自己配置)
private static final String DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource";
private DataSource buildDataSource(Map<String, String> dataSourceMap) {
try {
Object type = dataSourceMap.get("type");
if (type == null) {
type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
}
log.debug("data source type:{}", type);
Class<? extends DataSource> dataSourceType;
dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
String driverClassName = dataSourceMap.get("driver");
String url = dataSourceMap.get("url");
String username = dataSourceMap.get("username");
String password = dataSourceMap.get("password");
// 自定义DataSource配置
DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
.username(username).password(password).type(dataSourceType);
return factory.build();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源(需要继承AbstractRoutingDataSource)
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatabaseContextHolder.getDatabaseType();
}
}
@Value("#{'${slave.datasource.names}'.split(',')}")
private List<String> dsNameList;
public int monitor() {
// 默认数据源
if (heartBeatDatabase(Strings.EMPTY) == 0)
isError = true;
// 其他数据源
for (String dsName : dsNameList) {
if (heartBeatDatabase(dsName) == 0)
isError = true;
}
// 出现异常
if (isError) {
isError = false;
return 0;
}
return 1;
}
private int heartBeatDatabase(String dsName) {
try {
DatabaseContextHolder.setDatabaseType(dsName);
return monitorDao.select();
}
catch (Exception e) {
log.error("heartbeat error!");
try {
sendMail(dsName);
} catch (MessagingException e1) {
log.error("send mail error!", e);
}
}
return 0;
}
# mysql配置
spring.datasource.url=jdbc:mysql://130.51.23.249:3306/vacdb01?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root1
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# ds1,ds2等其他数据源,记得不要漏!否则下面配置了也是白配。
slave.datasource.names=ds1,ds2,ds3
# ds1
slave.datasource.ds1.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds1.url=jdbc:mysql://130.51.23.249:3306/flowable?useSSL=false
slave.datasource.ds1.username=flowable
slave.datasource.ds1.password=
# ds2
slave.datasource.ds2.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds2.url=jdbc:mysql://132.120.2.134:3300/motor?useSSL=false
slave.datasource.ds2.username=motor
slave.datasource.ds2.password=
# ds3
slave.datasource.ds3.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds3.url=jdbc:mysql://130.51.23.249:8066/VACDB?useUnicode=true&characterEncoding=utf-8
slave.datasource.ds3.username=vac
slave.datasource.ds3.password=
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/2464371/blog/3088920