путаница с транзакциями и msdtc

Я немного не понимаю, как транзакции и msdtc работают вместе.

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

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

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

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

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


person muhan    schedule 14.10.2009    source источник


Ответы (3)


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

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

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

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

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

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

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

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

Обратите внимание: если вы используете методы адаптера данных, они автоматически управляют вашим соединением, поэтому соединение закрывается или возвращается в пул соединений. В любом случае, если вызывается другая операция, транзакция будет переведена в транзакцию DTC. Дополнительные сведения см. В разделе System.Transactions и пул подключений.

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

Чтобы расширить объяснение @ 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 также могут помочь вам более эффективно обрабатывать ваши соединения и транзакции.

person Daniel    schedule 14.10.2009
comment
Блок доступа к данным корпоративной библиотеки может помочь, потому что он поддерживает внутренний список активных транзакций и их соединений (в классе TransactionScopeConnections). Одно и то же соединение используется в течение всего времени существования транзакции, поэтому транзакция не перерастает в распределенную транзакцию. Он также имеет то преимущество, что делает ваши интерфейсы более чистыми, поскольку вам не нужно передавать соединение каждому методу, который должен использовать соединение с базой данных. - person Randy supports Monica; 14.10.2009
comment
ДЛЯ пользователей SQLserver 2008: первый пример вашего кода не будет расширяться на SQLserver 2008. Он будет увеличиваться только в том случае, если вы не закроете первое соединение перед открытием второго (например, если вы вложите третье соединение с использованием statament внутри второго оператора using ). - person mipe34; 12.11.2012

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

Полная запись в блоге TableAdapters + Transactions 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 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" />

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

Создавать:

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()) 

Читать:

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
person Lewie    schedule 14.05.2010