2

多くのスレッドで一括挿入を試みました。linq を使用して 1 つの dataTable (「dt」と呼ばれる) の 1000 行を読み取った後、新しい dataTable を作成し、データベースに一括挿入しました。

スレッドを初期化するコードがあります。

        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}
4

1 に答える 1

2

ODP.Net Developer's Guide から、OracleBulkCopy クラスがダイレクト パス ロードを行うようです。その場合、マルチスレッド アプリケーションとの互換性はあまりありません。任意の時点で、特定のオブジェクトに対してダイレクト パス ロードを実行できるセッションは 1 つだけです。任意の時点で 1 つのスレッドだけが開いているトランザクションを持つようにスレッドをシリアル化できると思いますが、これはクライアントでのマルチスレッド化の目的を無効にする可能性が高いようです。一方、ダイレクト パス挿入はデータをロードする最も効率的な方法であるため、基本的には、ネットワーク経由でデータをポンプできる限り迅速にデータをロードできるはずです (もちろん、データベースがデータを高速に処理できると仮定します)。しかし、私はそれができると思います)。

于 2013-06-13T14:23:35.813 に答える