SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

SQL Database のデータベースをまたいだ分散トランザクションについて

leave a comment

3 月に GA した、SQL Database のデータベースをまたいだ分散トランザクションを実行するための機能である、Elastic Database Transaction について。

詳細は以下を参照してください。

Elastic Database Transactions are now generally available for Azure SQL Database
クラウド データベースにまたがる分散トランザクション

現状、SQL Database でデータベースをまたいだ、検索としては Elastic Database Query があります。
これは、外部テーブルとして他のデータベースのテーブルを定義することで「検索のみ」を可能とする機能となります。

Azure SQL Database エラスティック データベース クエリの概要 (プレビュー)

Elastic Database Transaction はデータベースをまたいだトランザクションを可能とするものですが、これは、外部テーブルを使用するのではなく、分散トランザクションを利用することで、変更を可能とするものです。

2016/8 時点では SQL のクエリベースでは対応しておらず (BEGIN DISTRIBUTED TRANSACTION は対応していない)、.NET Framework 4.6.1 以降を使用したコード的な対応が必要となります。

サポートされるのは、.NET アプリケーションからクライアント側で調整されるトランザクションだけです。将来的には、サーバー側の T-SQL サポート (BEGIN DISTRIBUTED TRANSACTION など) が予定されていますが、現時点では利用できません。

とありましたので、時間がたてば解消される可能性がありますが。

冒頭で紹介したドキュメントにも記載されていますが、以下のようなトランザクションスコープを使用して、複数のデータベースに対しての分散トランザクションを可能とします。

$constring1 = "Data Source=xxxxxxx.database.windows.net;Initial Catalog=DB1;Integrated Security=False;User ID=xxxxx;Password=xxxxxx"
$constring2 = "Data Source=xxxxxxx.database.windows.net;Initial Catalog=DB2;Integrated Security=False;User ID=xxxxx;Password=xxxxxx"
$con1 = New-Object System.Data.SqlClient.SqlConnection
$con1.ConnectionString = $constring1
$con2 = New-Object System.Data.SqlClient.SqlConnection
$con2.ConnectionString = $constring2
try{
    $transcope = New-Object System.Transactions.TransactionScope
    $con1.Open()
    $cmd1 = $con1.CreateCommand()
    $cmd1.CommandText = "CREATE TABLE test1(Col1 int);INSERT INTO test1 VALUES(1)"
    $cmd1.ExecuteNonQuery() > $null
    $con2.Open()
    $cmd2 = $con2.CreateCommand()
    $cmd2.CommandText = "CREATE TABLE test2(Col1 int);INSERT INTO test2 VALUES(1);WAITFOR DELAY '00:00:40'"
    $cmd2.ExecuteNonQuery() > $null
    $transcope.Complete()
}catch{
    Write-Output $_
}finally{
    if($transcope){
        $transcope.Dispose()
    }
}

上記のようなトランザクションを実行すると、SQL Database は分散トランザクションが行われるようになります。

select @@SERVERNAME,* from sys.dm_tran_active_transactions where dtc_state not in (3,4)
select @@SERVERNAME,* from sys.dm_tran_database_transactions where database_transaction_status = 1

 

同一の transaction_uow となっており、DTCXact として、分散トランザクションが実行されていることが確認できます。

image

同一のサーバー内の異なるデータベースであれば、特に設定はなく、トランザクションスコープを使用することができますが、異なるサーバーの場合は、「New-AzureRmSqlServerCommunicationLink」のコマンドレットを使用して、コミュニケーションリンクをサーバー間で設定する必要があります。

これは、「同一のサブスクリプション内の異なる SQL Database サーバー間でコミュニケーションリンクを設定」するためのものとなるため、異なるサブスクリプションのサーバー間では設定することはできません。

# 検証してみたところ、同一のサブスクリプションであれば、異なるリソースグループ / リージョンでも問題ありませんでした。

設定は以下のような形で行います。

Add-AzureRMAccount
$subscription = Get-AzureRMSubscription | Out-GridView -OutputMode Single
Select-AzureRmSubscription -SubscriptionId $subscription.SubscriptionId
$rgroup = Get-AzureRmResourceGroup | Out-GridView -OutputMode Single
New-AzureRmSqlServerCommunicationLink -ResourceGroupName $rgroup.ResourceGroupName -LinkName "DTCLink" -ServerName "ServerA" -PartnerServer "ServerB"

コマンドレット実行時にはサーバー名を指定するのですが「database.windows.net」を付与する必要はありません。

このコマンドレットを実行することで「ServerName」「PartnerServer」の両サーバー上で、コミュニケーションリンクが作成されます。

この設定が行われている場合は、分散トランザクションで使用する接続で異なる SQL Database のサーバーを指定した、分散トランザクションを実行することができるようになります。

# コミュニケーションリンクを作成してい場合、異なるサーバー間で分散トランザクションを実行するとエラーとなります。

今までまとめたことがなかったので軽くまとめてみました。

Share

Written by Masayuki.Ozawa

8月 20th, 2016 at 11:55 pm

Posted in SQL Database

Tagged with

Leave a Reply