Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Тема организации распределенных транзакций между различными составляющими системы затрагивается довольно часто. В серии последующих постов постараюсь рассказать о различных способах формирования транзакций для повышения интероперабельности системы. Поддержка в WCF спецификаций WS-* (в том числе WS-AtomicTransaction и WS-Coordination) в значительной степени облегчает поставленную задачу.
Первый пост затронет создание транзакций между CRL хранимой процедурой в SQL Server 2008 и Oracle 11g. Допустим, в организации над одним модулем системы работают несколько отделов. Отдел2 разрабатывает backend часть системы и предоставляет набор веб-сервисов, для вызова соответствующих операций. А отедл1 занимается frontend составляющей и должен использовать определенную комбинацию операций, опубликованных сервисов, для выполнения поставленной задачи (необходимо, чтобы при неуспешном выполнении какого-либо вызова сервиса откатывалась вся задача целиком). Пример подобной архитектуры приведен на рисунке:
Подобную схему достаточно просто реализовать:
- Транзакция инициализируется в хранимой процедуре proc1:
--корневая транзакция begin DISTRIBUTED transaction <код процедуры> в случае успешного выполнения commit transaction в случае ошибок rollback transaction |
- Далее в рамках этой транзакции вызывается CLR процедура на том же сервере:
EXEC <CLR хранимую процедуру> |
- CLR процедура обращается к WCF сервису или к нескольким WCF сервисам (в этот момент локальная транзакция становится распределенной):
[Microsoft.SqlServer.Server.SqlProcedure] public static void CallWS() { EndpointAddress address = new EndpointAddress("<адрес>"); WSHttpBinding binding = new WSHttpBinding(); binding.TransactionFlow = true; try { … //client proxy для WCF сервиса Service1Client client = new Service1Client(binding, address); client.Operation1(5); … } catch (System.Exception ex) { //откат корневой транзакции Transaction.Current.Rollback(); } } |
WCF использует wshttpbinding, обладающий поддержкой транзакций:
[ServiceContract(SessionMode = SessionMode.Required)] public interface IService1 { [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] string Operation1(int value); [OperationContract] [TransactionFlow(TransactionFlowOption.Mandatory)] string Operation2(int value); } public class Service1 : IService1 { #region IService1 Members [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)] public string Operation1 (int value) {} { <код метода: обращение к Oracle> OperationContext.Current.SetTransactionComplete(); } [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)] public string Operation2 (int value) { <код метода: обращение к Oracle> OperationContext.Current.SetTransactionComplete(); } #endregion } |
в конфигурационном файле сервиса так же включена поддержка «входящей» транзакции (атрибут transaction flow):
<bindings> <wsHttpBinding> <binding name="wsHttBinding1" transactionFlow="true" > </binding> </wsHttpBinding> </bindings> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttBinding1" contract="IService1"> |
подробнее о вызове WCF сервиса из CLR процедур см. "Call a WCF Service from SQLCLR"
из методов WCF сервиса идет обращение к Oracle:
для организации участия Oracle в распределенной транзакции необходимо сконфигурировать MSDTC, см. «How To Configure DTC to Support Oracle Transactions» и «Understanding XA Transactions».
При организации подобной распределенной транзакции не стоит забывать о высокой вероятности возникновения блокировок на доступ к данным, что может привести к значительному снижению производительности системы.
В следующий раз расскажу об использовании SQL Server Broker'а для выполнения похожей задачи.