注意這是一個抽象類!
package copyright.hang.shu.daily.sql;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.lang.StringUtils;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
// 繼承自javax.sql.DataSource
public abstract class DynamicDatasource implements DataSource {
// 采用線程變量存放目前使用的資料庫,如果不設定使用預設資料庫
private ThreadLocal<String> CURRENT_DATASOURCE =new ThreadLocal<>();
// Map中存放的是會用到的資料源
private Map<String,DataSource> dataSourceMap=new HashMap<>();
private final ReadWriteLock lock=new ReentrantReadWriteLock();
private String driverName;
private String formatUrl;
private String username;
private String password;
private String defaultDatabaseName;
private List<String> dynamicDatasourceNames;
public DynamicDatasource(String driverName, String formatUrl, String username, String password, String defaultDatabaseName, List<String> dynamicDatasourceNames) {
this.driverName = driverName;
this.formatUrl = formatUrl;
this.username = username;
this.password = password;
this.defaultDatabaseName = defaultDatabaseName;
this.dynamicDatasourceNames = dynamicDatasourceNames;
init();
}
// 初始化資料源
public void init() {
try {
lock.writeLock().lock();
dynamicDatasourceNames.add(defaultDatabaseName);
dynamicDatasourceNames.forEach(v->{
createConnection(v);
});
}finally {
lock.writeLock().unlock();
}
}
// 建立資料源
private void createConnection(String databaseName){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(driverName);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
// formatUrl中存在占位符,例如jdbc:mysql://127.0.0.1:3306/%s?useSSL=false&serverTimezone=UTC&&allowPublicKeyRetrieval=true
dataSource.setJdbcUrl(String.format(formatUrl,databaseName));
dataSource.setUser(username);
dataSource.setPassword(password);
dataSourceMap.put(databaseName,dataSource);
}
@Override
public Connection getConnection() throws SQLException {
try {
lock.readLock().lock();
if(CURRENT_DATASOURCE.get()==null){
return dataSourceMap.get(defaultDatabaseName).getConnection();
}
return dataSourceMap.get(CURRENT_DATASOURCE.get()).getConnection();
}finally {
lock.readLock().unlock();
}
}
// 添加資料源
public final void addDataSource(String name,DataSource dataSource) throws Exception {
try {
lock.writeLock().lock();
if(StringUtils.isBlank(name) || dataSource==null || dataSourceMap.containsKey(name)){
throw new Exception();
}
dataSourceMap.put(name,dataSource);
}finally {
lock.writeLock().unlock();
}
}
// 移除資料源
public final void removeDataSource(String name) throws Exception {
try {
lock.writeLock().lock();
dataSourceMap.remove(name);
}finally {
lock.writeLock().unlock();
}
}
// 設定目前線程使用的資料源
public void setCurrentDataSource(String name) throws Exception {
try {
lock.readLock().lock();
if(!dataSourceMap.containsKey(name)){
throw new Exception();
}
CURRENT_DATASOURCE.set(name);
}finally {
lock.readLock().unlock();
}
}
}