我已经阅读了AbstractRoutingDataSource以及this article动态绑定数据源的标准方法:
public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
它使用ThreadLocal
上下文持有者来“设置”DataSource:
public class CustomerContextHolder {
private static final ThreadLocal<CustomerType> contextHolder =
new ThreadLocal<CustomerType>();
public static void setCustomerType(CustomerType customerType) {
Assert.notNull(customerType, "customerType cannot be null");
contextHolder.set(customerType);
}
public static CustomerType getCustomerType() {
return (CustomerType) contextHolder.get();
}
// ...
}
我有一个非常复杂的系统,其中线程不一定在我的控制之下,比如说:
ItemReader
将使用为该特定作业设置的原始数据源(原始数据源必须绑定到某些存储库)ItemWriter
将使用为该特定作业设置的目标数据源(目标数据源也必须绑定到某些存储库)。 所以我对ThreadLocal
感到有点焦虑,特别是,我不确定是否会使用相同的线程来处理多个作业。如果发生这种情况,原始数据库和目标数据库可能会混合。
在处理多个线程时,如何以安全的方式动态“存储”和绑定数据源?
答案 0 :(得分:0)
我找不到一种方法来设置Spring与我的设置一起玩得很好并注入所需的DataSource
,所以我决定手动处理它。
我将我的存储库更改为原型,以便每次连接时都会构建一个新实例:
@Repository
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
我在顶级接口/实现中引入了新的setDataSource
和setSchema
方法,这些方法应该适用于多个实例/模式。
由于我使用spring-data-jdbc-repository我的setDataSource
方法,因此简单地用DataSource
包裹新JdbcTemplate
并传播更改。
setJdbcOperations(new JdbcTemplate(dataSource));
我的实现是直接从应用服务器获取DataSources
:
final Context context = new InitialContext();
final DataSource dataSource = (DataSource) context.lookup("jdbc/" + dsName);
最后,对于同一数据库实例下的多个模式,我使用特殊用户(具有正确的权限)登录并使用Oracle命令切换到所需的模式:
getJdbcOperations().execute("ALTER SESSION SET CURRENT_SCHEMA = " + schema);
虽然这违反了依赖性反转原则,但它能够很好地处理我的并发性要求。