最近、私たちはSQLトランザクションのタイムアウトと関連して非常に興味深い問題に直面しました。タイムアウトした文は本当に問題のために重要ではありませんが、それは、単一のINSERT文だったのwクライアントとの明示的なトランザクションをキーとしてGUIDを生成したO /:SQLトランザクションタイムアウトに対処するための防御的アプローチ
INSERT MyTable
(id, ...)
VALUES (<client-app-generated-guid>, ...)
は、我々はまた、インプレース再試行ポリシーを持っていますしたがって、コマンドがSqlExceptionで失敗した場合は、再試行されます。 SQL Server(Azure SQL)はいつも正常に動作せず、再試行中に多くの奇妙なPK違反エラーに遭遇しました。それらはを実際に正常にをコミットしてをコミットして、SQL Serverのトランザクションで(これにより、既にIDを取得しているため)挿入されました。私はSQLのタイムアウトはpurely client side conceptだから、もしクライアントがSqlCommandが失敗したと考えるなら、それはかもしれないし、そうでないかもしれないと理解している。を意味する。
クライアントの明示的なトランザクション制御は、TransactionScope
のようなラッピングステートメントを使用すると、このような問題の99%が修正されます。実際にCommitはかなり高速です。&安価な操作です。しかし、私はまだそこに警告を見る - タイムアウトはコミットステージでも起こりうる。このアプリケーションは、トランザクションが実際にコミットされたかどうかを推測することが不可能な状況(リトライの必要性を把握するため)にも、再び存在する可能性があります。
防弾でコードを書いて(そのような種類の問題に)、の一般ファッションをどうやって書いて、トランザクションがコミットされていないことが明確になったらリトライしてください。
using (var trx = new TransactionScope())
using (var con = GetOpenConnection(connectionString))
{
con.Execute("<some-non-idempotent-query>");
// what if Complete() times out?!
// to retry or not to retry?!
trx.Complete();
}
COMMIT TRANが実際に正常に実行されたという確認をクライアントがSQL Serverから受け取る前に、フレームワークコードがコミット済みトランザクションを99%報告する方法を持っていても、迅速にプラグをプルすることができます。 SQL AzureのSLA/Latencyのためだけに、これはSQL Azureでは問題が増え、On-premesisでは問題にはならないと思います。 あなたのコミットが成功したかどうかを伝える方法はありません。読み取り後の書き込みであっても、大量の環境で誰かの変更を単に取り上げる可能性があります。 – PhillipH
@PhillipH、ありがとう!そのような問題をいかに克服するか? –
あなたのコミットが失敗した場合、再試行処理ロジックで、 'INSERT ... WHERE NOT EXISTS(SELECT id FROM MyTable WHERE id = @id)'のように条件付きの再挿入が必要な場合があります。 – Alex