2009-10-14 2 views
8

У меня есть некоторое основное замешательство в отношении того, как транзакции и msdtc работают вместе.путаница о транзакциях и msdtc

У меня есть базовое приложение winforms server/client winforms. Приложение использует транзакцию для инкапсуляции нескольких команд sql, которые выполняются на сервере sql.

Приложение, похоже, отлично работает, когда я разрешаю доступ к сети только на сервере msdtc. Затем в один прекрасный день он прекратил работу, заявив, что доступ к сети не включен.

Теперь кажется, что мне нужно включить доступ к сети msdtc на клиентском компьютере и сервере для работы с транзакцией.

Служит ли служба клиента или сервера msdtc для транзакции? Или, может быть, и то и другое?

Есть ли у кого-нибудь указания, нужен ли доступ к сети msdtc как на клиенте, так и на сервере или просто на сервере?

ответ

10

Если вы используете MSDTC, вам понадобится клиент (приложение) и сервер (база данных) для запуска MSDTC, а также для правильной настройки.

Это может быть источником боли, особенно при работе с брандмауэрами. Если у вас возникли проблемы, см. Troubleshooting Problems with MSDTC. В нем говорится о BizTalk, но он применяется к MSDTC в целом. DTCPING - тоже ваш друг.

Теперь, если вы используете SQL Server 2005 и выше, имеете доступ только к одной базе данных, используете одно соединение с базой данных и не пропускаете транзакции между доменами приложений, тогда вам не требуется использование MSDTC. В этих обстоятельствах менеджер транзакций System.Transactions будет управлять вашими транзакциями для вас. Если произойдет какая-либо из предыдущих ситуаций, транзакция будет продвигаться в распределенную транзакцию (а менеджером транзакций будет MSDTC). См. Transaction Management Escalation для получения дополнительной информации.

Вообще лучше избегать использования MSDTC, если вам это не нужно. т. е. если вы имеете дело только с одной базой данных SQL Server 2005+, попробуйте разработать код, чтобы не использовать MSDTC. Помимо проблем с настройками, DTC налагает штраф за производительность, поскольку все вызовы MSDTC не работают в процессе работы вместе с накладными расходами двух фазовых протоколов фиксации (которые использует MSDTC).

С точки зрения того, что происходит в вашей конкретной ситуации, трудно сказать. Если ваш код не изменился, возможно, изменились правила брандмауэра? Я также видел, что обновление Windows изменило конфигурацию DTC (для обеспечения безопасности), которая вызвала проблему.

Обновления на основе комментариев:

Для продвижения сделки мониторинга или эскалации, если вы не используете распределенные транзакции я думаю, вы могли бы использовать некоторые из распределенных счетчиков производительности координатора транзакций для отслеживания совершенных сделок. Если вы тестируете, вы можете отключить MSDTC и посмотреть, не сработает ли ваш код. Другой способ - отслеживать транзакции в SQL Server. С точки зрения кодирования вы можете попытаться обработать событие DistributedTransactionStarted и выполнить некоторую регистрацию (но удалите этот код перед выходом на производство).

Для примера кода, используя одно соединение, перейдите на страницу TransactionScope в MSDN. В принципе, создайте TransactionScope, создайте SqlConnection, выполните некоторую работу с SqlConnection, закройте соединение, вызовите scope.Complete().

Обратите внимание, что если вы используете методы Data Adapter, они автоматически управляют вашим соединением, поэтому соединение закрывается или возвращается в пул соединений. В любом случае, если будет вызвана другая операция, транзакция будет переведена на транзакцию DTC. См. System.Transactions and connection pooling для более подробной информации.

+0

Благодарность за большой информации. Я бы не хотел использовать MSDTC. Я использую sql2005, 1 db, не передавая домены приложений, но не уверен, что я использую 1 соединение. Можно ли привести короткий пример транзакции с несколькими операторами sql, которые не будут добавлены в dtc? Есть ли инструмент или какой-либо другой способ узнать, повышены ли мои транзакции до msdtc? – muhan

7

Чтобы расширить @ объяснения Tuzo, вот пример команды, которая всегда будет обостряться:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    } 
    scope.Complete(); 
} 

На практике соединение и команда будет в другом классе, и т.д., но вы получите идея. Даже если строка подключения относится к одной и той же базе данных, она будет эскалации с использованием DTC, потому что это два соединения. Не-эскалацией сделка будет:

using(var scope = new TransactionScope()) 
{ 
    using(var conn = new SqlConnection(connString)){ 
    conn.Open(); 
    //...some command, etc. 
    //...some other command, etc. 
    } 
    scope.Complete(); 
} 

Это лучший код в любом случае, потому что вы открыть соединение, делать то, что вам нужно, и закрыть как можно скорее. Это означает, что вам нужно продумать управление соединениями. В зависимости от вашего приложения вы можете реализовать это по-другому. Например:

using(var scope = new TransactionScope()) 
using(var conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 
    var myService = new MyService(conn); 
    var myService2 = new MyService2(conn); 
    myService.DoSomething(); 
    myService2.DoSomething(); 
    scope.Complete(); 
} 

Существуют различные способы реализации этого. Блок приложений доступа к данным в корпоративной библиотеке и различные ORM также могут помочь вам более эффективно обрабатывать ваши соединения и транзакции.

+1

Блок доступа к данным в корпоративной библиотеке может помочь, поскольку он поддерживает внутренний список активных транзакций и их соединений (в классе TransactionScopeConnections). Такое же соединение используется для срока действия транзакции, поэтому транзакция не перерастает в распределенную транзакцию. Это также помогает сделать ваши интерфейсы более чистыми, так как вам не нужно передавать соединение по всем методам, которые необходимо использовать для подключения к базе данных. –

+1

Для пользователей SQLserver 2008: первый пример вашего кода не будет эскалироваться на SQLserver 2008. Он будет эскалироваться только в том случае, если вы не закрываете первое соединение перед открытием второго (например, если вы вставляете третий, используя statament во втором использовании заявление). – mipe34

0

Обновление: я нашел статью, в которой объясняется, почему транзакции продвигаются с использованием LTM в MSDTC, только при использовании GetData и Update на одном и том же адаптере данных в TransactionScope вместе с обходным путем.

Окончательный TableAdapters + Сделки блог http://blah.winsmarts.com/2006/06/18/the-definitive-tableadapters--transactions-blog-post.aspx

Я понимаю часть о наличии нескольких открытых соединений сразу эскалации сделки по распределению. Однако у меня возникла проблема, когда есть только одно соединение и один запрос к базе данных, которая ее наращивает. В хранимой процедуре нет никаких транзакций. Если кто-нибудь подскажет, я хотел бы услышать об этом. Из моего примера кода «adapter.Update (table)» инициирует распределенную транзакцию.

Я извлек из моего проекта извлечения из кода и упростил большую часть того, что происходило, и у меня все те же проблемы. Это в основном создает набор данных с адаптером таблицы и настраивает его с помощью хранимой процедуры для выбора, вставки и удаления. Я выбираю все связанные записи с конкретным пользователем. Затем, в зависимости от того, существует ли «myPPID» для одной из записей, я добавляю его или удаляю. Затем я вызываю метод обновления и вижу, что эскалация транзакций должна быть распределена путем просмотра статистики транзакций в службах компонентов.

Я использую Windows XP Pro SP3 и .Net Framework 3.5 для клиентской программы. Он подключается к базе данных SQL 2005 по локальной сети до Windows Server 2003 R2 Enterprise Edition с пакетом обновления 2 (SP2).

private void button1_Click(object sender, EventArgs e) 
{ 
int userId = 3; 
int myPPId = 881; 
using (TransactionScope ts = new TransactionScope()) 
{ 
    using (DataSet1TableAdapters.AssignedPPTableAdapter adapter 
    = new MSDTCPromotionTest.DataSet1TableAdapters.AssignedPPTableAdapter()) 
    { 
     using (DataSet1.AssignedPPDataTable table = adapter.GetData(userId)) 
     { 
      DataSet1.AssignedPPRow row = table.FindByUserIdmyPPId(
       userId, myPPId); 
      if (row == null) 
      { 
       table.AddAssignedPPRow(userId, myPPId, string.Empty, 
        string.Empty, true); 
      } 
      else 
      { 
       row.Delete(); 
      } 
      adapter.Update(table); 
     } 
     ts.Complete(); 
    } 
} 
} 

Строка подключения нет ничего особенного:

<add name="ConnectionString" connectionString=" 
Data Source=devdb; 
Initial Catalog=&quot;TEST MSDTC&quot;; 
Integrated Security=True" 
providerName="System.Data.SqlClient" /> 

Кроме того, хранимые процедуры, простые вызовы CRUD.

Создать:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Insert] 
(
    @UserId INT, 
    @myPPId int 
) 
AS 
SET NOCOUNT ON; 
INSERT INTO [UsermyPP] ([UserID],[myPPID],[DateCreated]) 
    VALUES (@UserId,@myPPId,GETutcDATE()) 

Read:

ALTER procedure [dbo].[p_UserForm_AssignedPP_SelectByUserId] 
(
    @UserId int 
) 
AS 
SELECT 
    [UserId], 
    [myPPId], 
    '' Title, 
    '' Abbreviation, 
    0 IsArchived 
from 
    UsermyPP unpp 
where 
    unpp.[userid] = @UserId 

Удалить:

ALTER procedure [dbo].[p_UserForm_AssignedPP_Delete] 
(
    @Original_UserId INT, 
    @Original_MyPPId INT 
) 
AS 
SET NOCOUNT ON; 
DELETE FROM usermypp WHERE [UserID] = @Original_UserId 
    AND [MyPPID] = @Original_MyPPId