使用单个ado.net查询查询多个数据库

时间:2009-12-30 13:12:40

标签: c# sql sql-server ado.net

我有分布式数据库架构,其中数据存储在多个SQL服务器中。

如何通过运行单个查询来选择/更新/删除。例如,“select * from employees”应该从我拥有的所有数据库中返回数据。

如何编写跨多个SQL服务器运行的单个查询,并将单个统一视图添加到我的Web服务器。

注意:由于SQL服务器的数量可能会在不同的时间发生变化,因此我正在寻找除链接查询以外的其他内容,因为大规模(向上或向下)管理链接查询是一件很大的痛苦

5 个答案:

答案 0 :(得分:6)

要与不同的数据库/连接通信,您需要通过TransactionScope进行分布式事务;幸运的是,这实际上比db-transactions 更容易(尽管你需要对System.Transactions.dll的引用):

using(TransactionScope tran = new TransactionScope()) {
    // lots of code talking to different databases / connections
    tran.Complete();
}

此外,TransactionScope自然地嵌套,SqlConnection自动登记,使其非常易于使用。

答案 1 :(得分:3)

使用TransactionScope

如果您打开与范围内不同服务器的连接,则该事务将被转换为分布式事务。

示例:

using (TransactionScope scope = new TransactionScope())
{
    conn1.Open(); //Open connection to db1
    conn2.Open(); //Open connection to db2

    // Don't forget to commit the transaction so it won't rollback
    scope.Complete()
}

答案 2 :(得分:0)

这里最好的解决方案是使用虚拟DBMS将多个后端混合到一个明显的后端 - 因此您的查询将转到Virtual DBMS,然后将其适当地中继到实际的数据存储。

OpenLink Virtuoso是一种选择。 Virtuoso打开与任何ODBC可访问(包括JDBC可访问,通过ODBC-to-JDBC Bridge)数据源的连接。

您的数据消费应用程序可以根据需要通过ODBC,JDBC,OLE-DB或ADO.NET连接到Virtuoso。所有远程链接对象(表,视图,存储过程等)都可通过所有数据访问机制获得。

虽然您可以使用此处概述的其他技术获得类似的结果,但这些技术要求最终用户了解所有有关后端数据结构的信息,并自行优化查询。使用Virtuoso,内置的基于成本的优化器将重新编写查询,以最小的网络流量提供最快的结果,基于在远程对象中链接时构建的虚拟架构。

我希望这有帮助!

泰德

ObDisclaimer:我为OpenLink Software工作,但不会直接从任何选择使用我们产品的人那里获益。

答案 3 :(得分:0)

除非您愿意插入可能与其他服务器(可能使用SQL CLR)协调的某种类型的中介(例如SQL Express实例),否则您无法执行单个查询所需的操作。但那太乱了。

简单地发出一堆异步请求,然后在它们到达时将响应合并到单个DataTable(或等效的)中会容易得多。通过使用本机ADO.NET样式的异步调用,所有查询都可以并行发生。当然,您需要在将数据读入单个DataTable时使用锁定。

答案 4 :(得分:0)

如果没有访问权限或特权来创建链接服务器,并使用所有Sql Server的合并JOINed Query生成View,请在所有Sql Server实例的同一查询语句中填充结果,并进行结果的合并。循环抛出所有数据库连接,并将收集的数据添加到合并的收集数据结构中,在此示例中,我选择DataTable:

DataTable consolidatedEmployees = new DataTable();
foreach(ConnectionStringSettings cs in ConfigurationManager.ConnectionStrings)
{
    consolidatedEmployees.Merge(
          SelectTransaction("select * from employees", cs.ConnectionString));
}

使用此方法示例来查询基于ADO.NET的任何SQL Server数据库:

/// <summary>
/// Method to execute SQL Query statements with
/// Transaction scope using isolation level to select read commited data
/// </summary>
/// <param name="query">SQL Query statement</param>
/// <param name="connString">Connections String</param>
internal DataTable SelectTransaction(string query, string connString)
{
    DataTable tableResult = null;
    SqlCommand cmd = null;
    SqlConnection conn = null;
    SqlDataAdapter adapter = null;
    TransactionOptions tranOpt = new TransactionOptions();
    tranOpt.IsolationLevel = IsolationLevel.ReadCommitted;
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, tranOpt))
    {
        tableResult = new DataTable();
        try
        {
            conn = new SqlConnection(connString);
            conn.Open();
            cmd = new SqlCommand(query, conn);
            adapter = new SqlDataAdapter(cmd);
            adapter.Fill(tableResult);
            break;
        }
        catch (Exception ex)
        {
            scope.Dispose();
            throw new Exception("Erro durante a transação ao banco de Dados.", ex);
        }
        finally
        {
            if (null != adapter)
            {
                adapter.Dispose();
            }
            if (null != cmd)
            {
                cmd.Dispose();
            }
            if (null != conn)
            {
                conn.Close();
                conn.Dispose();
            }
        }
        scope.Complete();
    }
    return tableResult;
}

使用此解决方案,仅需注意复制的数据,便需要在合并结果上做出明显的区分。