Я провел несколько тестов с тех пор, как задал этот вопрос, и нашел большинство, если не все ответы самостоятельно, поскольку никто не ответил. Пожалуйста, дайте мне знать, если я что-то пропустил.
Q1: Автоматически ли включается соединение в транзакцию?
Да, если в строке подключения не указано enlist=false
. Пул соединений находит подходящее соединение. Пригодное для использования соединение - это соединение, не включенное в транзакцию, или соединение, включенное в ту же транзакцию.
Q2: Если я сейчас открою (и запустил команды) второе соединение с идентичной строкой соединения, каковы будут отношения между этим вторым соединением и первым, если таковые имеются?
Второе соединение - это независимое соединение, которое участвует в той же транзакции. Я не уверен во взаимодействии команд в этих двух подключениях, поскольку они работают с одной и той же базой данных, но я думаю, что ошибки могут возникать, если команды выполняются на обоих одновременно: такие ошибки, как Контекст транзакции используется другим сеансом
Q3: Будет ли автоматическое включение этого второго соединения в текущую область транзакции привести к эскалации транзакции в распределенную транзакцию?
Да, он перерастает в распределенную транзакцию, поэтому включение более одного соединения, даже с одной и той же строкой соединения, превращает его в распределенную транзакцию, что может быть подтверждено проверкой ненулевого идентификатора GUID в Transaction.Current.TransactionInformation.DistributedIdentifier
.
* Обновление: я где-то читал, что это исправлено в SQL Server 2008, поэтому MSDTC не используется, когда одна и та же строка подключения используется для обоих подключений (пока оба подключения не открыты одновременно). Это позволяет вам открывать соединение и закрывать его несколько раз в рамках транзакции, что может более эффективно использовать пул соединений, открывая соединения как можно позже и закрывая их как можно скорее.
Q4: Если я начну выполнять команды в соединении сейчас, будет ли оно автоматически включено в текущую область транзакции?
Нет. Соединение, открытое, когда не было активной области транзакции, не будет автоматически добавлено в вновь созданную область транзакции.
Q5: Если не указан, будут ли команды, которые я выполняю в соединении, теперь участвовать в внешней транзакции?
Нет. Если вы не открываете соединение в области транзакции или не зачисляете существующее соединение в область действия, ТРАНЗАКЦИИ НЕ БУДУТ. Ваше соединение должно быть автоматически или вручную включено в область транзакции, чтобы ваши команды могли участвовать в транзакции.
Q6: Если команды в этом соединении не участвуют в текущей транзакции, будут ли они зафиксированы, даже если откатят текущую область транзакции?
Да, команды в соединении, не участвующие в транзакции, фиксируются как выданные, даже если код выполняется в блоке области транзакции, для которого был выполнен откат. Если соединение не включено в текущую область транзакции, оно не участвует в транзакции, поэтому фиксация или откат транзакции не повлияет на команды, выданные для соединения, не указанного в области транзакции ... as этот парень узнал. Это очень сложно обнаружить, если вы не разбираетесь в процессе автоматического зачисления: это происходит только тогда, когда соединение открывается внутри активной области транзакции.
В7: Приведенный выше метод явно включает ранее существовавшее соединение в текущую внешнюю транзакцию, так что команды, которые я выполняю в соединении, теперь участвуют в внешней транзакции?
да. Существующее соединение можно явно включить в текущую область транзакции, вызвав EnlistTransaction(Transaction.Current)
. Вы также можете подключить соединение к отдельному потоку в транзакции, используя DependentTransaction, но, как и раньше, я не уверен, как могут взаимодействовать два соединения, участвующие в одной транзакции с одной и той же базой данных ... и могут возникать ошибки, и конечно, второе включенное соединение приводит к эскалации транзакции до распределенной транзакции.
В8: что произойдет, если существующее соединение уже было задействовано в транзакции, когда я вызвал вышеуказанный метод? Может возникнуть ошибка?
Может возникнуть ошибка. Если использовалось TransactionScopeOption.Required
и соединение уже было включено в транзакцию области транзакции, то ошибки нет; фактически для области не создается новая транзакция, и количество транзакций (@@trancount
) не увеличивается. Если, однако, вы используете TransactionScopeOption.RequiresNew
, то при попытке включить соединение в новую транзакцию области транзакции вы получите полезное сообщение об ошибке: Соединение в настоящее время содержит транзакцию в списке. Завершите текущую транзакцию и повторите попытку. И да, если вы завершите транзакцию, в которой установлено соединение, вы можете безопасно включить соединение в новую транзакцию.
* Обновление: если вы ранее вызывали BeginTransaction
в соединении, при попытке зачисления в новую транзакцию области транзакции выдается немного другая ошибка: Невозможно зачислить в транзакцию, поскольку в соединении выполняется локальная транзакция. Завершите локальную транзакцию и повторите попытку. С другой стороны, вы можете безопасно вызвать BeginTransaction
на SqlConnection
, когда он включен в транзакцию области транзакции, и это фактически увеличит @@trancount
на единицу, в отличие от использования параметра Required для области вложенной транзакции, которая не вызывает ее увеличения. Интересно, что если вы затем продолжите создавать другую область вложенной транзакции с параметром Required
, вы не получите ошибку, потому что ничего не изменится в результате уже наличия активной транзакции области транзакции (помните, что @@trancount
не увеличивается, когда транзакция области транзакции уже активен, и используется параметр Required
).
В9: Если существующее соединение уже было зачислено в транзакцию, и я НЕ вызвал вышеуказанный метод для его включения, будут ли какие-либо команды, которые я выполняю на нем, участвовать в его существующей транзакции, а не в текущей области транзакции?
да. Команды участвуют в любой транзакции, в которой зарегистрировано соединение, независимо от того, какая активная область транзакции находится в коде C #.
person
Triynko
schedule
21.05.2010