增加数据库主备自动切换功能
This commit is contained in:
parent
e8ebe5db61
commit
6b4e43b159
@ -55,12 +55,24 @@
|
||||
</dependency>
|
||||
<!-- cglib end -->
|
||||
|
||||
<!-- springboot freemarker start -->
|
||||
<!-- freemarker start -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
<!-- springboot freemarker end -->
|
||||
<!-- freemarker end -->
|
||||
|
||||
<!-- durid start -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid</artifactId>
|
||||
</dependency>
|
||||
<!-- durid end -->
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>mysql</groupId>-->
|
||||
<!-- <artifactId>mysql-connector-java</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -0,0 +1,188 @@
|
||||
package ink.wgink.common.datasource;
|
||||
|
||||
import com.alibaba.druid.filter.config.ConfigFilter;
|
||||
import com.alibaba.druid.filter.encoding.EncodingConvertFilter;
|
||||
import com.alibaba.druid.filter.logging.CommonsLogFilter;
|
||||
import com.alibaba.druid.filter.logging.Log4j2Filter;
|
||||
import com.alibaba.druid.filter.logging.Log4jFilter;
|
||||
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
|
||||
import com.alibaba.druid.filter.stat.StatFilter;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.wall.WallFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @ClassName: StandbyMySqlDataSource
|
||||
* @Description: 主备mysql数据库源
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/11/28 9:32 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Primary
|
||||
@Component
|
||||
@ConfigurationProperties("spring.datasource.druid")
|
||||
public class StandbyDataSource extends DruidDataSource implements InitializingBean {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StandbyDataSource.class);
|
||||
private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(2);
|
||||
|
||||
@Autowired
|
||||
private DataSourceProperties basicProperties;
|
||||
|
||||
private boolean lastInited;
|
||||
/**
|
||||
* 备库url连接
|
||||
*/
|
||||
private String[] standbyUrls;
|
||||
private volatile int standbyIndex = 0;
|
||||
|
||||
@Override
|
||||
public void init() throws SQLException {
|
||||
lastInited = inited;
|
||||
super.init();
|
||||
// 第一次初始化
|
||||
if (!lastInited && inited) {
|
||||
// 如果没有配置,不启用主备切换
|
||||
if (standbyUrls == null || standbyUrls.length == 0) {
|
||||
return;
|
||||
}
|
||||
scheduledExecutorService.schedule(new ValidateUrlTask(), 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证连接
|
||||
*/
|
||||
private class ValidateUrlTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
// 备库下标
|
||||
while (true) {
|
||||
// 如果这个数据源被关闭了,就结束这个定时任务
|
||||
if (isClosed()) {
|
||||
LOG.debug("Jdbc connection closed");
|
||||
break;
|
||||
}
|
||||
//如果这个数据源已经被初始化了,同时连接异常才进行处理
|
||||
if (isInited() && !isConnectionActive()) {
|
||||
// 主库有问题时,切换备库
|
||||
LOG.debug("Change standby urls, index:{}", standbyIndex);
|
||||
String standbyUrl = standbyUrls[standbyIndex];
|
||||
changeUrl(standbyUrl);
|
||||
standbyIndex++;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换连接
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
private void changeUrl(String url) {
|
||||
LOG.debug("jdbc url: {}", url);
|
||||
inited = false;
|
||||
setUrl(url);
|
||||
}
|
||||
|
||||
public void setStandbyUrls(String[] standbyUrls) {
|
||||
this.standbyUrls = standbyUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断连接是否存活
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isConnectionActive() {
|
||||
try (Connection conn = getConnection();
|
||||
Statement stmt = conn.createStatement();
|
||||
) {
|
||||
stmt.execute("select 1");
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
LOG.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (super.getUsername() == null) {
|
||||
super.setUsername(this.basicProperties.determineUsername());
|
||||
}
|
||||
|
||||
if (super.getPassword() == null) {
|
||||
super.setPassword(this.basicProperties.determinePassword());
|
||||
}
|
||||
|
||||
if (super.getUrl() == null) {
|
||||
super.setUrl(this.basicProperties.determineUrl());
|
||||
}
|
||||
|
||||
if (super.getDriverClassName() == null) {
|
||||
super.setDriverClassName(this.basicProperties.getDriverClassName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addStatFilter(StatFilter statFilter) {
|
||||
super.filters.add(statFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addConfigFilter(ConfigFilter configFilter) {
|
||||
super.filters.add(configFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addEncodingConvertFilter(EncodingConvertFilter encodingConvertFilter) {
|
||||
super.filters.add(encodingConvertFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addSlf4jLogFilter(Slf4jLogFilter slf4jLogFilter) {
|
||||
super.filters.add(slf4jLogFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addLog4jFilter(Log4jFilter log4jFilter) {
|
||||
super.filters.add(log4jFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addLog4j2Filter(Log4j2Filter log4j2Filter) {
|
||||
super.filters.add(log4j2Filter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addCommonsLogFilter(CommonsLogFilter commonsLogFilter) {
|
||||
super.filters.add(commonsLogFilter);
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void addWallFilter(WallFilter wallFilter) {
|
||||
super.filters.add(wallFilter);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user