增加数据库主备自动切换功能
This commit is contained in:
parent
e8ebe5db61
commit
6b4e43b159
@ -55,12 +55,24 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<!-- cglib end -->
|
<!-- cglib end -->
|
||||||
|
|
||||||
<!-- springboot freemarker start -->
|
<!-- freemarker start -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.freemarker</groupId>
|
||||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
<artifactId>freemarker</artifactId>
|
||||||
</dependency>
|
</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>
|
</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