跨雲端資料庫的分散式交易

適用於:Azure SQL 資料庫Azure SQL 受控執行個體

本文說明使用彈性資料庫交易,以讓您跨 Azure SQL Database 和 Azure SQL 受控執行個體的雲端資料庫執行分散式交易。

在本文中,「分散式交易」和「彈性資料庫交易」字詞視為同義字,並會交替使用。

注意

您也可以使用 Azure SQL 受控實例的分散式交易協調器 (DTC) 在混合環境中執行分散式交易。

概觀

針對 Azure SQL Database 與 Azure SQL 受控執行個體的彈性資料庫交易,可讓您跨多個資料庫執行交易。 彈性資料庫交易適用於使用 ADO .NET 的 .NET 應用程式,而且與以往熟悉使用 System.Transaction類別的程式設計經驗整合。 如要取得程式庫,請參閱 .NET Framework 4.6.1 (Web 安裝程式)。

此外, Transact-SQL 中也提供 SQL 受控實例分散式交易。

在內部部署環境中,這類情況通常需要執行 Microsoft Distributed Transaction Coordinator (MSDTC) 服務。 因為 MSDTC 不適用於 Azure SQL Database,所以協調分散式交易的功能已直接整合至 SQL Database 和 SQL 受控執行個體。 不過,對於 SQL 受控執行個體,您也可以使用 適用於 Azure SQL 受控執行個體的分散式交易協調器(DTC),在多種混合環境之間執行分散式交易,例如跨受控執行個體、SQL Server 執行個體、其他關聯式資料庫管理系統(RDBMS)、自訂應用程式,以及託管於任何可與 Azure 建立網路連線之環境中的其他交易參與者。

應用程式可以連線至任何資料庫來啟動分散式交易,而其中一個資料庫或伺服器會明確地協調分散式交易,如下圖所示。

Azure SQL Database 使用彈性資料庫交易的分散式交易圖表。

常見的案例

彈性資料庫交易使應用程式能夠對儲存在多個不同資料庫中的資料進行原子性變更。 SQL Database 和 SQL 受控執行個體都支援 C# 和 .NET 的用戶端開發體驗。 使用 Transact-SQL 的伺服器端體驗 (以預存程序或伺服器端指令碼撰寫的程式碼) 僅適用於 SQL 受控執行個體。

重要

不支援在 Azure SQL 資料庫與 Azure SQL 管理實例之間執行彈性資料庫交易。 彈性資料庫交易只能跨越 SQL 資料庫中的一組資料庫,或跨受管理實例的資料庫一組。

彈性資料庫交易針對下列案例:

  • Azure 的多資料庫應用程式:在此案例中,資料在 SQL Database 或 SQL 受控執行個體中的多個資料庫垂直分割,使得不同種類的資料位於不同的資料庫。 部分作業需要變更資料,而這些資料保存在兩個以上的資料庫中。 應用程式使用彈性資料庫交易來協調跨資料庫的變更,並確保原子性。
  • Azure 的分區化資料庫應用程式:在此案例中,資料層會使用 彈性資料庫用戶端程式庫 或自行分區,將資料以水平方式分割到 SQL Database 或 SQL 受控執行個體中的多個資料庫。 一個顯著的應用案例是當變更跨越租戶時,需要對分片多租戶應用程式進行原子變更。 例如,將資料從一個租戶移轉到另一個租戶,且兩者分別位於不同的資料庫中。 第二種情況是為了因應大型租戶的容量需求而採用細粒度分片,而這通常意味著某些原子操作需要跨同一租戶所使用的多個資料庫執行。 第三種情況是對跨資料庫複寫的參考資料進行原子更新。 這類原子性、交易式作業如今已可跨多個資料庫進行協調。 彈性資料庫交易使用兩階段提交以確保交易在資料庫間的原子性。 如果交易在單一交易中同時涉及的資料庫少於 100 個,便很適合使用這種方式。 這些限制不是強制規定,但超出這些限制時,彈性資料庫交易的效能和成功率必然下降。

安裝和移轉

彈性資料庫交易的功能是透過 .NET 程式庫 System.Data.dll 和 System.Transactions.dll 的更新提供。 這些 DLL 會在必要時使用兩階段認可,以確保原子性。 若要使用彈性資料庫交易來開始開發應用程式,請安裝 .NET Framework 4.6.1 或更新版本。 在舊版 .NET Framework 上執行時,交易無法升級為分散式交易,將會引發例外狀況。

安裝後,即可透過連線至 SQL Database 和 SQL 受控執行個體的 System.Transactions,使用分散式交易 API。 如果您有使用這些 API 的現有 MSDTC 應用程式,請在安裝 4.6.1 Framework 之後,將這些現有應用程式重新建置為適用於 .NET 4.6。 如果您的專案目標設為 .NET 4.6,便會自動使用新版 Framework 中更新的 DLL;而分散式交易 API 呼叫在搭配連線至 SQL Database 或 SQL 受控執行個體時,現在將可成功執行。

請記得,彈性資料庫交易不需要安裝 MSDTC。 而且,彈性資料庫交易是由服務直接管理。 這可大幅簡化雲端案例,因為 MSDTC 的部署不需使用 SQL Database 或 SQL 受控執行個體的分散式交易。 第 4 節更詳細地說明如何將彈性資料庫交易和必要的 .NET Framework 連同您的雲端應用程式一起部署到 Azure。

Azure 雲端服務的 .NET 安裝

Azure 提供多種方案來託管 .NET 應用程式。 如需不同供應項目的比較,請參閱 Azure App 服務、雲端服務與虛擬機器之比較。 如果供應項目的客體 OS 小於彈性交易所需的 .NET 4.6.1,則您必須將客體 OS 升級至 4.6.1。

對於 Azure App 服務,目前不支援升級至客體 OS。 對於 Azure 虛擬機器,只要登入 VM,並執行最新的 .NET Framework 的安裝程式即可。 對於 Azure 雲端服務,您需要將新版 .NET 的安裝包含在您部署的啟動工作中。 在雲端服務角色上安裝 .NET中說明概念和步驟。

.NET 4.6.1 的安裝程式在 Azure 雲端服務的啟動載入程式期間,可能需要比 .NET 4.6 安裝程式更多的暫存記憶體。 若要確保安裝成功,您必須在 [LocalResources] 區段中的檔案中 ServiceDefinition.csdef 增加 Azure 雲端服務的暫存記憶體,以及啟動工作的環境設定,如下列範例所示:

<LocalResources>
...
    <LocalStorage name="TEMP" sizeInMB="5000" cleanOnRoleRecycle="false" />
    <LocalStorage name="TMP" sizeInMB="5000" cleanOnRoleRecycle="false" />
</LocalResources>
<Startup>
    <Task commandLine="install.cmd" executionContext="elevated" taskType="simple">
        <Environment>
    ...
            <Variable name="TEMP">
                <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='TEMP']/@path" />
            </Variable>
            <Variable name="TMP">
                <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='TMP']/@path" />
            </Variable>
        </Environment>
    </Task>
</Startup>

.NET 開發經驗

多重資料庫應用程式

下列範例程式代碼使用熟悉的 .NET System.Transactions程式設計體驗。 類別 TransactionScope 會在 .NET 中建立環境交易。 (「環境事務」是存在於目前線程中的一個事務。)在TransactionScope中開啟的所有連線都會參與該事務。 如果有不同的資料庫參與,交易會自動提升為分散式交易。 將範圍設為 complete 以表示提交,即可控制交易的結果。

using (var scope = new TransactionScope())
{
    using (var conn1 = new SqlConnection(connStrDb1))
    {
        conn1.Open();
        SqlCommand cmd1 = conn1.CreateCommand();
        cmd1.CommandText = string.Format("insert into T1 values(1)");
        cmd1.ExecuteNonQuery();
    }
    using (var conn2 = new SqlConnection(connStrDb2))
    {
        conn2.Open();
        var cmd2 = conn2.CreateCommand();
        cmd2.CommandText = string.Format("insert into T2 values(2)");
        cmd2.ExecuteNonQuery();
    }
    scope.Complete();
}

分區化資料庫應用程式

SQL Database 和 SQL 受控執行個體的彈性資料庫交易也支援協調分散式交易,您可使用彈性資料庫用戶端程式庫的 OpenConnectionForKey 方法,開啟擴增資料層的連線。 請考慮這樣的情況:您需要確保涉及多個不同分區索引鍵值的變更之交易一致性。 與承載不同分區鍵值的各個分區之間的連線,都是透過 OpenConnectionForKey 進行仲介。 在一般情況下,這些連線可能會連到不同的分片,因此若要確保交易保證,就需要分散式交易。

下列程式碼範例說明此方法。 這裡假設使用一個名為 shardmap 的變數,用來表示彈性資料庫用戶端程式庫中的分區對應表:

using (var scope = new TransactionScope())
{
    using (var conn1 = shardmap.OpenConnectionForKey(tenantId1, credentialsStr))
    {
        SqlCommand cmd1 = conn1.CreateCommand();
        cmd1.CommandText = string.Format("insert into T1 values(1)");
        cmd1.ExecuteNonQuery();
    }
    using (var conn2 = shardmap.OpenConnectionForKey(tenantId2, credentialsStr))
    {
        var cmd2 = conn2.CreateCommand();
        cmd2.CommandText = string.Format("insert into T1 values(2)");
        cmd2.ExecuteNonQuery();
    }
    scope.Complete();
}

Transact-SQL 開發經驗

使用 Transact-SQL 的伺服器端分散式交易僅適用於 Azure SQL 受控執行個體。 分散式交易只能在屬於同一 伺服器信任群組的實例間執行。 在此情節中,受控執行個體需要使用連結的伺服器來互相參考。

下列範例 Transact-SQL 程式碼使用 BEGIN DISTRIBUTED TRANSACTION 啟動分散式交易。

    -- Configure the Linked Server
    -- Add one Azure SQL Managed Instance as Linked Server
    EXEC sp_addlinkedserver
        @server='RemoteServer', -- Linked server name
        @srvproduct='',
        @provider='MSOLEDBSQL', -- Microsoft OLE DB Driver for SQL Server
        @datasrc='managed-instance-server.46e7afd5bc81.database.windows.net' -- SQL Managed Instance endpoint

    -- Add credentials and options to this Linked Server
    EXEC sp_addlinkedsrvlogin
        @rmtsrvname = 'RemoteServer', -- Linked server name
        @useself = 'false',
        @rmtuser = '<login_name>',         -- login
        @rmtpassword = '<secure_password>' -- password

    USE AdventureWorks2022;
    GO
    SET XACT_ABORT ON;
    GO
    BEGIN DISTRIBUTED TRANSACTION;
    -- Delete candidate from local instance.
    DELETE AdventureWorks2022.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    -- Delete candidate from remote instance.
    DELETE RemoteServer.AdventureWorks2022.HumanResources.JobCandidate
        WHERE JobCandidateID = 13;
    COMMIT TRANSACTION;
    GO

結合 .NET 和 Transact-SQL 開發體驗

使用 System.Transaction 類別的 .NET 應用程式可以結合 TransactionScope 類別與 Transact-SQL 陳述式 BEGIN DISTRIBUTED TRANSACTION。 在 TransactionScope 中,執行 BEGIN DISTRIBUTED TRANSACTION 的內部交易會明確升階為分散式交易。 此外,當 TransactionScope 內開啟第二個 SqlConnection 時,它會隱含地升階為分散式交易。 啟動分散式交易後,所有後續的交易要求 (無論來自 .NET 或 Transact-SQL) 都會聯結父代分散式交易。 因此,BEGIN 陳述式起始的所有巢狀交易範圍最後會存在於同一個交易中,且 COMMIT/ROLLBACK 陳述式會對整體結果產生下列影響:

  • COMMIT 陳述式對 BEGIN 陳述式起始的交易範圍沒有任何影響,所以在 TransactionScope 物件上叫用 Complete() 方法前,不會有認可的結果。 如果 TransactionScope 物件在完成之前遭到銷毀,則在此範圍內所做的所有變更都會回復。
  • ROLLBACK 陳述式會使整個 TransactionScope 回復。 之後在 TransactionScope 中登錄新交易,及 TransactionScope 物件上叫用 Complete() 的任何嘗試都會失敗。

以下範例是使用 Transact-SQL 明確升階交易至分散式交易。

using (TransactionScope s = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(DB0_ConnectionString)
    {
        conn.Open();

        // Transaction is here promoted to distributed by BEGIN statement
        //
        Helper.ExecuteNonQueryOnOpenConnection(conn, "BEGIN DISTRIBUTED TRAN");
        // ...
    }

    using (SqlConnection conn2 = new SqlConnection(DB1_ConnectionString)
    {
        conn2.Open();
        // ...
    }

    s.Complete();
}

範例以下顯示了一筆交易,當在 TransactionScope 中啟動第二個 SqlConnection 時,自動升階為分散式交易。

using (TransactionScope s = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(DB0_ConnectionString)
    {
        conn.Open();
        // ...
    }

    using (SqlConnection conn = new SqlConnection(DB1_ConnectionString)
    {
        // Because this is second SqlConnection within TransactionScope transaction is here implicitly promoted distributed.
        //
        conn.Open();
        Helper.ExecuteNonQueryOnOpenConnection(conn, "BEGIN DISTRIBUTED TRAN");
        Helper.ExecuteNonQueryOnOpenConnection(conn, lsQuery);
        // ...
    }

    s.Complete();
}

SQL Database 的交易

支援跨 Azure SQL Database 不同伺服器間的彈性資料庫交易。 當交易跨越伺服器界限時,參與其中的伺服器首先必須建立相互通訊關係。 一旦建立通訊關聯性之後,任一部伺服器中的任何資料庫都可以和另一部伺服器中的資料庫一起參與彈性交易。 如果是跨兩個以上伺服器的交易,任何一組伺服器都必須具備通訊關聯性。

使用下列 PowerShell Cmdlet 管理跨伺服器的通訊關聯性,以進行彈性資料庫交易:

  • New-AzSqlServerCommunicationLink:使用此 Cmdlet 在 Azure SQL Database 中建立兩部伺服器之間的新通訊關聯性。 此關聯性是對稱的,也就是說,這兩部伺服器彼此都可以起始交易。
  • Get-AzSqlServerCommunicationLink:使用此 Cmdlet 擷取現有的通訊關聯性及其屬性。
  • Remove-AzSqlServerCommunicationLink:使用此 Cmdlet 移除現有的通訊關聯性。

SQL 受控執行個體的交易

支援跨多個執行個體中的資料庫進行分散式交易。 當交易跨越受控執行個體的界限時,參與的執行個體彼此之間必須具有相互的安全性與通訊關係。 這是透過建立 伺服器信任群組來完成的,這可以透過 Azure 入口網站、Azure PowerShell 或 Azure CLI 來完成。 如果實例不在同一個虛擬網路上,你必須設定 虛擬網路對等 ,且網路安全群組的入站與出站規則必須允許所有參與的虛擬網路使用 5024 和 11000-12000 埠。

Azure 入口網站上 Azure SQL 受控實例中 SQL 信任群組的螢幕快照。

下圖顯示一個伺服器信任群組,其中包含可使用 .NET 或 Transact-SQL 執行分散式交易的受控執行個體:

使用 Azure SQL 受控實例的彈性交易的分散式交易圖表。

監視交易狀態

使用動態管理檢視 (DMV) 監視進行中彈性資料庫交易的狀態和進度。 所有與交易相關的 DMV 都適用於 SQL Database 和 SQL 受控執行個體中的分散式交易。 關於對應的 DMV 清單,請參見 交易相關動態管理檢視與功能。

這些 DMV 特別有用:

  • sys.dm_tran_active_transactions:列出目前作用中的交易及其狀態。 UOW(工作單位)欄可識別出屬於同一個分散式交易的不同子交易。 相同分散式交易內的所有交易具有相同的 UOW 值。 如需詳細資訊,請參閱 sys.dm_tran_active_transactions (Transact-SQL) 。
  • sys.dm_tran_database_transactions:提供有關交易的附加資訊,例如在記錄檔中的交易位置。 如需詳細資訊,請參閱 sys.dm_tran_database_transactions (Transact-SQL)。
  • sys.dm_tran_locks:提供目前由進行中交易所持有之鎖定的相關信息。 如需詳細資訊,請參閱 sys.dm_tran_locks (Transact-SQL)。

限制

下列限制目前適用於 Azure SQL Database 中的彈性資料庫交易:

  • 僅支援 SQL Database 中跨資料庫的交易。 其他 X/Open XA 資源提供者和 SQL Database 之外的資料庫無法參與彈性資料庫交易。 這表示彈性資料庫交易無法延伸到內部部署 SQL Server 和 Azure SQL Database。 對於內部部署的分散式交易,請繼續使用 MSDTC。
  • 僅支援來自 .NET 應用程式的用戶端協調交易。 T-SQL 如 BEGIN DISTRIBUTED TRANSACTION 的伺服器端支援已規劃,但尚無法使用。
  • 不支援跨 WCF 服務的交易。 例如,您有執行交易的 WCF 服務方法。 納入交易範圍內的呼叫將會失敗,因為 System.ServiceModel.ProtocolException。

下列限制目前適用於 Azure SQL 受控實例中的分散式交易(也稱為彈易或原生支援的分散式交易):

  • 使用此技術時,僅支援受控執行個體中跨資料庫的交易。 針對可能包含 Azure SQL 受控實例外部 X/Open XA 資源提供者和資料庫的其他所有案例,您應該為 Azure SQL 受控實例設定分散式交易協調器 (DTC)。
  • 不支援跨 WCF 服務的交易。 例如,您有執行交易的 WCF 服務方法。 將此呼叫包含在交易範圍內會失敗,並出現 System.ServiceModel.ProtocolException。
  • Azure SQL 受管理實例必須是 伺服器信任群組 的一部分,才能參與分散式交易。
  • 伺服器信任群組的限制會影響分散式交易。
  • 參與分散式交易的受管理實例必須透過私有端點(使用部署的虛擬網路的私有 IP 位址)連接,並且必須透過私有完全限定的網域名稱(FQDN)互相引用。 用戶端應用程式可以使用私人端點的分散式交易。 此外,如果 Transact-SQL 利用參考私人端點的連結伺服器,用戶端應用程式也可以在公用端點上使用分散式交易。 下圖將說明這項限制。

私人端點連線網路和限制的圖表。