注意这是一个抽象类!
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();
}
}
}