上午,
我已成功使用基于Marten Deinum's Post的配置 动态连接(或创建和连接)仅在运行时已知的dbs。
我遇到的问题是现在间歇性地无法在dbs之间切换。第一个始终有效,但是输入日志代码显示第一个正确创建,然后第二个或第三个未在dataSource == null
中触发MdyDataSourceFactory
部分 - 如果进程认为它是相同的db,则会出现不会改变,但在某些时候它会触发并连接到后续的数据库!
在dbs之间运行一个简单的JUnit测试切换工作正常(代码正确触发,dbs切换和select语句按预期返回不同的id结果)。
在批处理作业步骤tasklet中调用它。该进程获取resultSets(摘要表)的计数并连接到db。对于每个resultSet,它调用db注册表并且如果存在 - 返回现有的或创建一个新的并返回。
我的动态db xml是:
<bean id="mdyDSRegistry" class="com.k12knowledge.db.MdyDataSourceFactory" />
<bean id="mdyDSTargetSource" class="com.k12knowledge.db.ContextSwappableMdyTargetSource">
<constructor-arg type="java.lang.Class">
<value>javax.sql.DataSource</value>
</constructor-arg>
<property name="targetRegistry" ref="mdyDSRegistry"></property>
</bean>
<bean id="proxyMdyDataSource" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>javax.sql.DataSource</value>
</list>
</property>
<property name="targetSource">
<ref bean="mdyDSTargetSource" />
</property>
</bean>
MdyDataSourceFactory是:
public class MdyDataSourceFactory implements TargetRegistry {
private ConcurrentMap<String, DataSource> map = new ConcurrentHashMap<String, DataSource>();
@Override
public DataSource getTarget(String context) {
IClientDs client = MdyContextHolder.getClientDs();
Assert.notNull(client, "Client was not set.");
String key = client.getUrl();
DataSource dataSource = map.get(key);
if (dataSource == null) {
System.out.println("dataSource == null - creating new");
dataSource = getDataSource(client);
dataSource = map.putIfAbsent(key, dataSource);
if (dataSource == null) {
// put success
dataSource = map.get(key);
}
}
System.out.println("client key: " + key);
return dataSource;
}
private DataSource getDataSource(IClientDs client) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(client.getDriver());
dataSource.setUrl(client.getUrl());
dataSource.setUsername(client.getUsername());
dataSource.setPassword(client.getPassword());
dataSource.setValidationQuery("/* ping */");
dataSource.setMaxActive(10);
dataSource.setMaxIdle(5);
dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
dataSource.setRemoveAbandoned(true);
dataSource.setRemoveAbandonedTimeout(20);
dataSource.setTimeBetweenEvictionRunsMillis(34000);
dataSource.setMinEvictableIdleTimeMillis(55000);
try {
System.out.println("dataSource " + client.getUrl() + " closed ? " + dataSource.getConnection().isClosed());
} catch (SQLException e) {
e.printStackTrace();
}
return dataSource;
}
}
有一次我认为我使用的密钥存在问题(某些数据库的名称只有1个字母不同)。然后我尝试在密钥的前面添加一个UUID,看看是不是问题 - 没有变化。
真的很困惑为什么它不起作用......任何指针都非常感激。
感谢您的关注。
ContextHolder
public abstract class ContextHolder {
private static final ThreadLocal<IClientDs> holder = new ThreadLocal<IClientDs>();
public static void setClientDs(IClientDs context) {
LoggerFactory.getLogger(ContextHolder.class).debug("context set '{}'", context);
holder.set(context);
}
public static IClientDs getClientDs() {
return (IClientDs) holder.get();
}
}