com.github.javaclub.cdl.client.group.DefaultDBSelector Maven / Gradle / Ivy
package com.github.javaclub.cdl.client.group;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.sql.DataSource;
import com.github.javaclub.cdl.client.common.DataSourceHolder;
import com.github.javaclub.cdl.client.common.DataSourceWrapper;
import com.github.javaclub.cdl.client.util.SQLMonitors;
public class DefaultDBSelector extends AbstractDBSelector {
private List dataSourceHolderList = new ArrayList();
private AtomicInteger rid = new AtomicInteger();
private boolean isMaster;
@Override
protected DataSourceHolder findDataSourceWrapperByIndex(int dataSourceIndex) {
boolean result = true;
try{
SQLMonitors.entry(isMaster ? "write":"read");
for (DataSourceHolder holder : dataSourceHolderList) {
if (holder.getDsw().getDataSourceIndex() == dataSourceIndex) {
return holder;
}
}
result = false;
return null;
}finally{
SQLMonitors.exit(isMaster ? "write":"read", result);
}
}
@Override
protected T tryExecuteInternal(Map failedDataSources, DataSourceTryer tryer, int times, Object... args)
throws SQLException {
List exceptions = new ArrayList(0);
if (failedDataSources != null) {
exceptions.addAll(failedDataSources.values());
times = times - failedDataSources.size();
for (SQLException e : failedDataSources.values()) {
if (!exceptionSorter.isExceptionFatal(e)) {
return tryer.onSQLException(exceptions, exceptionSorter, args);
}
}
}
// 默认重试一次
times = 2;
DataSourceHolder lastDsHolder = null;
DataSourceHolder dsHolder;
while ((dsHolder = getRandomDataSourceHolder(lastDsHolder)) != null && --times >= 0) {
boolean result = true;
try {
SQLMonitors.entry(isMaster ? "write":"read");
lastDsHolder = dsHolder;
if (dsHolder.isNotAvailable) {
boolean toTry = System.currentTimeMillis() - dsHolder.lastRetryTime > retryBadDbInterval;
if (toTry && dsHolder.lock.tryLock()) {
try {
T t = tryer.tryOnDataSource(dsHolder.dsw, args);
dsHolder.isNotAvailable = false;
return t;
} finally {
dsHolder.lastRetryTime = System.currentTimeMillis();
dsHolder.lock.unlock();
}
} else { // 此库暂不能使用
continue;
}
} else {
return tryer.tryOnDataSource(dsHolder.dsw, args);
}
} catch (SQLException e) {
result = false;
exceptions.add(e);
boolean isFatal = exceptionSorter.isExceptionFatal(e);
if (isFatal) {
dsHolder.isNotAvailable = true;
}
if (!isFatal) {
// 如果不是数据库不可用异常,或者不要求重试,直接抛出
break;
}
}finally{
SQLMonitors.exit(isMaster ? "write":"read", result);
}
}
if (exceptions.isEmpty()) { // 所有的数据库都不能使用
exceptions.add(new SQLException("not found available dataSource"));
}
return tryer.onSQLException(exceptions, exceptionSorter, args);
}
public DataSourceHolder getRandomDataSourceHolder(DataSourceHolder curDataSourceHolder) {
if (dataSourceHolderList.isEmpty()) {
return null;
}
if (dataSourceHolderList.size() == 1) {
if (curDataSourceHolder == null) {
return dataSourceHolderList.get(0);
} else { // 避免重复使用相同ds
return null;
}
}
if (rid.get() > Integer.MAX_VALUE - 10000) {
rid.set(0);
}
for (int i = 0; i < dataSourceHolderList.size(); i++) {
int index = rid.incrementAndGet() % dataSourceHolderList.size();
// 避免重复使用相同ds
if (curDataSourceHolder == null || !curDataSourceHolder.equals(dataSourceHolderList.get(index))) {
return dataSourceHolderList.get(index);
}
}
return null;
}
public void addDataSourceHolder(DataSourceHolder dataSourceHolder) {
if (isMaster) { // 写库,只有一个
dataSourceHolderList.add(dataSourceHolder);
} else {
if (dataSourceHolder.getDsw().getReadWeight().r > 0) { // 读库
for (int i = 0; i < dataSourceHolder.getDsw().getReadWeight().r; i++) { // 按照权重添加
dataSourceHolderList.add(dataSourceHolder);
}
if (dataSourceHolderList.size() > 2) { // 随机打散
Collections.shuffle(dataSourceHolderList);
}
}
}
}
public void setMaster(boolean isMaster) {
this.isMaster = isMaster;
}
@Override
public DataSourceWrapper getDataSourceWrapperForMeta() {
if(!dataSourceHolderList.isEmpty()){
return dataSourceHolderList.get(0).getDsw();
}
return null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy