2013-06-13 2 views
2

많은 스레드로 bulkinsert를 수행하려고했습니다. linq을 사용하여 하나의 dataTable ('dt'라고 함)의 1000 행을 읽은 후 새 dataTable을 만들고 데이터베이스에 bulkinsert를 수행했습니다. 당신이 볼 수 있듯이문제 : 다중 스레드 대량 삽입

 ManualResetEvent[] doneEvents = new ManualResetEvent[10]; 
     BancoDAO[] fibArray = new BancoDAO[10]; 

     for (int i = 0; i < 10; i++) 
     { 
      doneEvents[i] = new ManualResetEvent(false); 
      BancoDAO bd = new BancoDAO() 
      { 
       _doneEvent = doneEvents[i], 
       dataTable = (dt.AsEnumerable() 
        .Skip(i * 1000) 
        .Take(1000) 
        ).CopyToDataTable<DataRow>() 
      }; 
      fibArray[i] = bd; 
      ThreadPool.QueueUserWorkItem(bd.ThreadPoolCallback, i); 
     } 

     WaitHandle.WaitAll(doneEvents); 

가 삽입이 BancoDAO 클래스에 발생

스레드를 초기화하는 코드가있다. 여기 코드는 다음과 같습니다

public DataTable dataTable = new DataTable(); 
    public ManualResetEvent _doneEvent; 

    public void ThreadPoolCallback(Object threadContext) 
    { 
     int threadIndex = (int)threadContext; 
     GravaTabelaThread(dataTable); 
     _doneEvent.Set(); 
    } 

    public static void GravaTabelaThread(DataTable dt) 
    { 
      OracleConnection cteste = new OracleConnection(ConfigurationManager.ConnectionStrings["TesteUpload"].ToString()); 
      cteste.Open(); 
      OracleBulkCopy bcp = new OracleBulkCopy(cteste); 
      bcp.DestinationTableName = "MAG_T_SORTIMENTO2"; 

      foreach (KeyValuePair<string, string> k in ColumnMappings()) 
      { 
       bcp.ColumnMappings.Add(k.Key, k.Value); 
      } 
      try 
      { 
       bcp.WriteToServer(dt); 
       bcp.Dispose(); 
      } 
      catch (Exception ex) 
      { 
      } 
      cteste.Close(); 
      //Now I open and close the connection everytime after doing the bulkinsert in the database. 
      //I'm not using anymore the same connection. 
    } 

문제는 : 일부 스레드가 ... 몇 번이 예외 불면 (나는 영어로 포르투갈어에서 오라클 메시지를 번역 할 수 있습니다 데이터베이스에 값을 삽입, 그래서 명심하시기 바랍니다

{Oracle.DataAccess.Client.OracleException Error in row '1' column '1' 
ORA-39776: API fatal error, wrong directoty way when loading the table USR_TRANSF.MAG_T_SORTIMENTO2 
ORA-39781: Loads of direct path stream are not allowed after another context loading the same table was to be terminated in Oracle.DataAccess.Client.OracleBulkCopy.PerformBulkCopy() 
    in Oracle.DataAccess.Client.OracleBulkCopy.WriteDataSourceToServer() 
    in Oracle.DataAccess.Client.OracleBulkCopy.WriteToServer(DataTable table, DataRowState rowState) 
    in Oracle.DataAccess.Client.OracleBulkCopy.WriteToServer(DataTable table) 
    in UploadArquivo.BancoDAO.GravaTabelaThread(DataTable dt) at c:\Users\Rafael.pinho\Desktop\UploadArquivo\UploadArquivo\UploadArquivo\BancoDAO.cs:linha 49} 
+0

새 연결을 사용하라는 오류가 표시됩니다. – RBarryYoung

+0

지금 작동 중입니다. 위의 코드를 솔루션으로 업데이트했습니다. @RBarryYoung에게 감사합니다. – Phelps

답변

2

그것은 OracleBulkCopy class does a direct-path load 그 ODP.Net 개발자 가이드에서 나타납니다이는 "의역")입니다. 그렇다면 다중 스레드 응용 프로그램과 실제로 호환되지 않습니다. 언제든지 특정 개체에 대한 직접 경로로드를 수행 할 수있는 세션은 하나뿐입니다. 난 당신이 스레드를 직렬화 할 수 있도록 한 스레드가 열려있는 트랜잭션을 어느 시점에서 시간이 있지만 클라이언트에서 멀티 스레드 목적을 패배 가능성이 높습니다 보인다. 다른 한편, 직접 경로 삽입은 데이터를로드하는 가장 효율적인 방법이기 때문에 기본적으로 네트워크를 통해 데이터를 펌프 할 수있는 속도로 데이터를로드 할 수 있어야합니다 (물론 데이터베이스가 신속하게 데이터를 처리 할 수 ​​있다고 가정 할 때) 그러나 나는 그것을 할 수 있다고 가정 할 것이다).