【问题标题】:Asynchronous multiple query from different datasources or databases来自不同数据源和数据库的异步多重查询
【发布时间】:2013-04-20 11:15:58
【问题描述】:

我很难找到合适的解决方案:

我有几个结构相同但数据不同的数据库。当我的网络应用程序执行查询时,它必须为每个数据库分离这个查询并异步执行它,然后聚合来自所有数据库的结果并将其作为单个结果返回。另外,我希望能够传递将在其中执行查询的数据库列表,并且我还希望传递查询执行的最大过期时间。结果还必须包含每个数据库的元信息,例如额外的执行时间。

如果可以使用其他数据源,例如具有特定 API 的远程 Web 服务,而不是关系数据库,那就太好了。

我使用 Spring/Grail 并且需要 java 解决方案,但我很乐意听取任何建议。

UPD:我想找到准备好的解决方案,可能是框架或类似的东西。

【问题讨论】:

  • 好的,请问有什么问题?你试过什么?是什么阻止你这样做?
  • 所以,我想找到准备好的解决方案,也许是框架或类似的东西。但我发现它只有一件事是 UnityJDBC,但它只适用于关系数据库,没有元信息和查询的过期时间

标签: java grails asynchronous datasource multiple-databases


【解决方案1】:

这是基本的面向对象。您需要从您用来实现的机制(数据库查询或 Web 服务调用)中抽象出您试图实现的目标 - 加载数据。

这样的设计通常会涉及一个接口,该接口定义了可以做什么的契约,然后是多个实现类,这些类根据它们的实现来实现。

例如,您最终会得到一个类似于以下内容的界面:

public interface DataLoader
{
    public Collection<Data> loadData() throws DataLoaderException;
}

然后您将拥有JdbcDataLoaderWebServiceDataLoader 等实现。在您的情况下,您需要另一种类型的实现,给定一个或多个DataLoader 实例,运行每个实例以汇总结果。这个实现看起来像:

public class AggregatingDataLoader implements DataLoader
{
  private Collection<DataLoader> dataLoaders;
  private ExecutorService executorService;

  public AggregatingDataLoader(ExecutorService executorService, Collection<DataLoader> dataLoaders)
  {
    this.executorService = executorService;
    this.dataLoaders = dataLoaders;
  }

  public Collection<Data> loadData() throws DataLoaderException
  {
    Collection<DataLoaderCallable>> dataLoaderCallables = new ArrayList<DataLoaderCallable>>();

    for (DataLoader dataLoader : dataLoaders)
    {
      dataLoaderCallables.add(new DataLoaderCallable(dataLoader));  
    } 

    List<Future<Collection<Data>>> futures = executorService.invokeAll(dataLoaderCallables);

    Collection<Data> data = new ArrayList<Data>(); 
    for (Future<Collection<Data>> future : futures)
    {
       add.addAll(future.get());
    }      

    return data;
  }

  private class DataLoaderCallable implements Callable<Collection<Data>>
  {
    private DataLoader dataLoader;

    public DataLoaderCallable(DataLoader dataLoader)
    {
      this.dataLoader = dataLoader;  
    }

    public Collection<Data> call()
    {
      return dataLoader.load(); 
    }
  }
}

您需要为此添加一些超时和异常处理逻辑,但您明白了要点。

另一件重要的事情是您的调用代码应该只使用DataLoader 接口,以便您可以在测试期间交换不同的实现或使用模拟。

【讨论】:

  • 感谢您的详细回答。我同意,实现起来并不难,但我认为我可以为我的案例找到类似 mapreduce 框架(如 hadoop)的东西。但看来我得自己写了。
  • 执行 map-reduce 的工作是知道如何映射要减少的数据集和 reduce 本身 - 两者都将针对您的问题。像 Hadoop 或大多数分布式缓存技术将执行 map-reduce,但您仍然需要实现它们的接口来完成实际工作。我的建议,如果您可以在不引入框架(额外依赖项)的情况下轻松做到这一点,那么请保持简单并忽略框架。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-24
  • 2017-12-17
  • 1970-01-01
  • 1970-01-01
  • 2013-11-23
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多