Как использовать одну SqlTransaction для нескольких SqlConnections в .NET?
-
03-07-2019 - |
Вопрос
Решение
По какой причине вы не используете одно соединение и несколько команд (фактически одна команда воссоздается в цикле)? Может быть, это решение будет работать для вас:
public static void CommandExecNonQuery(SqlCommand cmd,
string query, SqlParameter[] prms)
{
cmd.CommandText = query;
cmd.Parameters.AddRange(prms);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
static void Main(string[] args)
{
string insertQuery =
@"INSERT TESTTABLE (COLUMN1, COLUMN2) " +
"VALUES(@ParamCol1, @ParamCol2)";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
using (SqlCommand command =
connection.CreateCommand())
{
SqlTransaction transaction = null;
try
{
// BeginTransaction() Requires Open Connection
connection.Open();
transaction = connection.BeginTransaction();
// Assign Transaction to Command
command.Transaction = transaction;
for (int i = 0; i < 100; i++)
CommandExecNonQuery(command, insertQuery,
new SqlParameter[] {
new SqlParameter("@ParamCol1", i),
new SqlParameter("@ParamCol2", i.ToString()) });
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
finally
{
connection.Close();
}
}
}
}
Также смотрите
Транзакции сервера Sql - ADO.NET 2.0 - принятие и откат - использование Заявление - IDisposable
Другие советы
Вы не указали, используете ли вы .NET 2.0, но я сделаю это предположение. Пример кода C # 3.0 приведен ниже:
using (var tx = new TransactionScope()) {
// Execute multiple DB statements inside here
ts.Complete();
}
Если какой-либо из операторов БД завершится неудачно, ts.complete никогда не будет достигнут, и транзакция будет автоматически откатана в конце оператора using. Однако одно предостережение от этого подхода заключается в том, что в конечном итоге вы будете использовать DTC, если будете использовать несколько соединений, что означает снижение производительности.
Изменено для изменения SqlTransaction на TransactionScope
Пример принудительного использования одного соединения SQL, чтобы избежать использования кода DTC:
using (var tx = new TransactionScope())
using (var db = new SqlConnection(connString)) {
// Command 1
using (var cmd = db.CreateCommand()) {
cmd.CommandText = "select...";
using (var reader = cmd.ExecuteReader()) {
// Process results or store them somewhere for later
}
}
// Command 2
using (var cmd = db.CreateCommand()) {
cmd.CommandText = "select...";
using (var reader = cmd.ExecuteReader()) {
// Process results or store them somewhere for later
}
}
// Command 3
using (var cmd = db.CreateCommand()) {
cmd.CommandText = "select...";
using (var reader = cmd.ExecuteReader()) {
// Process results or store them somewhere for later
}
}
tx.Complete();
}
Транзакции создаются для соединения и не имеют никакой области, кроме той, в которой они созданы, поэтому вы не можете делать то, о чем просите. Выполните рефакторинг, чтобы можно было выполнять вставки последовательно для соединения, а не одновременно, или реализовывать другой механизм для достижения отката (например, таблица вставленных ключей, которую можно использовать для поиска, чтобы удалить вставленные записи, если позже ошибка возникнет в процесс) р>
Я не думаю, что транзакция может охватывать несколько соединений. Р>
В чем причина выполнения нескольких вставок в отдельных соединениях? Я думаю, вы бы хотели, чтобы они были в одном соединении, как обычно.