Каковы наилучшие практики для транзакций на С#.Net 2.0. Какие классы следует использовать? Каковы подводные камни, которые нужно искать и т.д. Все, что совершает и откатывает вещи. Я только начинаю проект, где мне может понадобиться сделать некоторые транзакции, вставляя данные в БД. Любые ответы или ссылки на даже основные вещи о транзакциях приветствуются.
Транзакции в .net
Ответ 1
Существует 2 основных вида сделок; транзакции подключения и внешние транзакции. Сделка соединения (например, SqlTransaction) привязана непосредственно к соединению db (например, SqlConnection), что означает, что вам нужно продолжать передавать соединение - в некоторых случаях ОК, но не разрешает "создавать/использовать/выпускать", использование и не разрешает работу с несколькими db. Пример (отформатирован для пробела):
using (IDbTransaction tran = conn.BeginTransaction()) {
try {
// your code
tran.Commit();
} catch {
tran.Rollback();
throw;
}
}
Не слишком грязно, но ограничивается нашей связью "conn". Если мы хотим обратиться к различным методам, нам нужно передать "conn".
Альтернативой является внешняя транзакция; new в .NET 2.0, объект TransactionScope (System.Transactions.dll) позволяет использовать его в различных операциях (подходящие поставщики автоматически зачисляют во внешней транзакции). Это позволяет легко встраиваться в существующий (не транзакционный) код и разговаривать с несколькими провайдерами (хотя DTC будет задействован, если вы поговорите с более чем одним).
Например:
using(TransactionScope tran = new TransactionScope()) {
CallAMethodThatDoesSomeWork();
CallAMethodThatDoesSomeMoreWork();
tran.Complete();
}
Обратите внимание, что эти два метода могут обрабатывать свои собственные соединения (open/use/close/dispose), но они беззвучно станут частью внешней транзакции без необходимости пропускать что-либо.
Если ваши ошибки кода, Dispose() вызывается без Complete(), поэтому он будет откат. Ожидаемое вложение и т.д. Поддерживается, хотя вы не можете откатить внутреннюю транзакцию, но завершите внешнюю транзакцию: если кто-то недоволен, транзакция прерывается.
Другим преимуществом TransactionScope является то, что он не привязан к базам данных; любой поставщик транзакций может использовать его. WCF, например. Или есть даже некоторые объектные модели, совместимые с TransactionScope (например, классы .NET с возможностью отката - возможно, проще, чем память, хотя я никогда не использовал этот подход сам).
В целом, очень, очень полезный объект.
Некоторые оговорки:
- В SQL Server 2000 TransactionScope немедленно переключится на DTC; это исправлено в SQL Server 2005 и выше, оно может использовать LTM (намного меньше служебных), пока вы не поговорите с 2 источниками и т.д., когда он повышен до DTC.
- Существует сбой, что означает, что вам может понадобиться настроить строку подключения
Ответ 2
protected void Button1_Click(object sender, EventArgs e)
{
using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True"))
{
connection1.Open();
// Start a local transaction.
SqlTransaction sqlTran = connection1.BeginTransaction();
// Enlist a command in the current transaction.
SqlCommand command = connection1.CreateCommand();
command.Transaction = sqlTran;
try
{
// Execute two separate commands.
command.CommandText =
"insert into [doctor](drname,drspecialization,drday) values ('a','b','c')";
command.ExecuteNonQuery();
command.CommandText =
"insert into [doctor](drname,drspecialization,drday) values ('x','y','z')";
command.ExecuteNonQuery();
// Commit the transaction.
sqlTran.Commit();
Label3.Text = "Both records were written to database.";
}
catch (Exception ex)
{
// Handle the exception if the transaction fails to commit.
Label4.Text = ex.Message;
try
{
// Attempt to roll back the transaction.
sqlTran.Rollback();
}
catch (Exception exRollback)
{
// Throws an InvalidOperationException if the connection
// is closed or the transaction has already been rolled
// back on the server.
Label5.Text = exRollback.Message;
}
}
}
}
Ответ 3
Вы также можете перенести транзакцию в свою собственную хранимую процедуру и обработать ее таким образом, а не выполнять транзакции в самом С#.
Ответ 4
если вам просто нужно это для db-связанных вещей, некоторые OR Mappers (например, NHibernate) поддерживают трансактины из коробки по умолчанию.
Ответ 5
Это также зависит от того, что вам нужно. Для основных транзакций SQL вы можете попробовать выполнить транзакции TSQL, используя BEGIN TRANS и COMMIT TRANS в своем коде. Это самый простой способ, но он имеет сложность, и вы должны быть осторожны, чтобы совершить правильное (и откат).
Я бы использовал что-то вроде
SQLTransaction trans = null;
using(trans = new SqlTransaction)
{
...
Do SQL stuff here passing my trans into my various SQL executers
...
trans.Commit // May not be quite right
}
Любая ошибка выскочит из using
и транзакция всегда будет совершать или откатываться (в зависимости от того, что вы скажете ей). Самая большая проблема, с которой мы столкнулись, заключалась в том, чтобы она всегда выполнялась. Использование позволяет ограничить объем транзакции.