2013-06-13 2 views
0

Я создаю механизм для массового вставки (импорта) большого количества новых записей в базу данных ORACLE. Я использую несколько потоков и зависимых операций:Получение исключения «дублирующий идентификатор транзакции» при использовании Transaction.Current.DependentClone

Создание нитей:

const int ThreadCount = 4; 
using (TransactionScope transaction = new TransactionScope()) 
{ 
    List<Thread> threads = new List<Thread>(threadCount); 
    for (int i = 0; i < ThreadCount; i++) 
    { 
     Thread thread = new Thread(WorkerThread); 
     thread.Start(Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete)); 
     threads.Add(thread); 
    } 
    threads.ForEach(thread => thread.Join()); 
    transaction.Complete(); 
} 

Метод, который делает фактическую работу:

private void WorkerThread(object transaction) 
{ 
    using (DependentTransaction dTx = (DependentTransaction)transaction) 
    using (TransactionScope ts = new TransactionScope(dTx)) 
    { 
     // The actual work, the inserts on the database, are executed here. 
    } 
} 

Во время этой операции, я получаю исключение типа System.Data.OracleClient.OracleException с сообщением ORA-24757: duplicate transaction identifier.

Что я делаю неправильно? Я неправильно выполняю зависимую транзакцию? Это несовместимо с Oracle? Если да, есть ли рабочий стол?

ответ

1

Я не знаю, почему у получить это исключение, но работа вокруг может быть:

const int ThreadCount = 4; 
using (var connection = new OracleConnection(MyConnectionstring)) 
{ 
    connection.Open(); 
    using (var transaction = connection.BeginTransaction()) 
    { 
     List<Thread> threads = new List<Thread>(ThreadCount); 
     for (int i = 0; i < ThreadCount; i++) 
     { 
      Thread thread = new Thread(WorkerThread); 
      thread.Start(transaction); 
      threads.Add(thread); 
     } 
     threads.ForEach(thread => thread.Join()); 

     transaction.Commit(); 
    } 
} 

и рабочий класс будет выглядеть примерно так:

private void WorkerThread(object transaction) 
{ 
    OracleTransaction trans = (OracleTransaction) transaction; 

    using (OracleCommand command = trans.Connection.CreateCommand()) 
    { 
     command.CommandText = "INSERT INTO mytable (x) values (1) "; 
     command.ExecuteNonQuery(); 
    } 
} 
+0

Пока я apreciate усилия, это не очень помогает. Поскольку соединение не может использоваться несколькими потоками, соединение будет «блокировать» соединение при выполнении его (не) запроса. Это приводит к еще более медленному решению, чем однопоточная среда ... –

+0

Я еще немного подумал о вашем решении. Это будет только ускорять все больше и больше, когда часть «подготовки» (например, импорт, сбор данных и т. Д.) Становится все больше и больше. Не резьбовой INSERT ускорит его, а тот факт, что часть «подготовки» может быть разделена на несколько потоков. После того, как запись «подготовлена» (параллельно), она может быть записана в базу данных, которая станет в вашем случае очередью заблокированных операций INSERT. –

Смежные вопросы