MySql用8个线程抛出不同的异常

时间:2012-05-30 13:57:20

标签: c# mysql multithreading

所以在我的程序中发生了一些奇怪的事情。 所以我有多个线程与ThreadPool.QueueUserWorkItem排队。直到最近,线程池中的每个线程都会从一个数组中接收List<MyObject>,并且每个线程都将列表插入到我的MySql数据库中。最近对列表处理的更改迫使我创建一个包含所有小列表的大列表(使用List.AddRange)。然后我将此列表拆分为较小的部分,并将每个部分发送到之前的相同插入线程。现在,一切都与 7个或更少的线程完美配合。我的程序最初使用8个线程来执行所有操作,因为我记得读过线程应该是2 *个核心的东西。

现在,当我运行8个线程的程序时,它开始抛出各种似乎随机抛出的MySqlExceptions。 示例:所有线程查询从未更改的某个表。有些线程将返回select * from table fine,而1个随机线程会突然说该表不存在或者我的DataTable为空,这是不可能的,因为它是相同的表和查询。我有各种其他异常,比如OpenDataReader,Connection必须有效和打开,NullReferenceException试图关闭Connection等。

注意:每个线程都拥有与数据库的单独连接,因此不应相互冲突。

由于代码很长,我不确定是否粘贴代码。另外,我不太确定我的代码是什么,因为我说当我使用8个或更多线程时出现问题。 我不想采取简单的方法,只使用7个线程,因为可能有一些东西,我不知道这将导致将来当我实施额外的更改时出现问题。 如果有人要我展示具体的作品,我可以相应地编辑我的问题。

public MySqlDb 
{ 
    MySqlConnection mySqlConnection;
    MySqlDataAdapter mySqlDataAdapter;
    public int ExecuteInsert(string query)
    {
        using (MySqlCommand mySqlCommand = new MySqlCommand())
        {
            mySqlCommand.CommandText = query;
            using (mySqlCommand.Connection = GetConnection())
            {
                  mySqlCommand.Connection.Open();
                  using (mySqlDataAdapter = new MySqlDataAdapter())
                  {
                       try
                       {
                           mySqlDataAdapter.InsertCommand = mySqlCommand;
                           return mySqlDataAdapter.InsertCommand.ExecuteNonQuery();
                       }
                       catch (MySqlException mse)
                       {
                            logger.Warn("MySqlException : " + mse.Message);
                            throw;
                       }
                       finally
                       {
                            mySqlCommand.Connection.Close();
                       }
                  }
             }
         }
    }

    public MySqlConnection GetConnection()
    {
        connectionString.DefaultCommandTimeout = 3600;
        myConnection = new MySqlConnection(connectionString.GetConnectionString(true));
        return myConnection;
    }
}

我的连接字符串是从我的.xml文件加载的,只是一个基本的连接字符串

<add name="MySqlConnectionString" providerName="System.Data.SqlClient" connectionString="Server=server_name;Database=db_name; Uid=my_username;Pwd=my_pass;charset=utf8;port=3306;" </add>

更新1:因此,在尝试找出问题之后,我一次减少了我执行的插入量。每个线程都包含一个表示MySql表的Object。从打印出查询的例外情况之一来看,似乎Insert()被调用两次而没有执行实际的mySql.ExecuteInsert(query.ToString())。除非某些变量在线程之间共享,即使每个变量都有自己独立的对象,我也没有看到它应该这样做的任何理由。以下是相关代码。如果这个问题太长而无法作为正确的问题阅读,请对此进行评论以及如何进行评论。

class PartsInventories 
{
    MySqlDb mySql;

    public const String PARTS_INVENTORIES = "parts_inventories";

    // find the optimum of best perfomance while not raising MAX_PACKETS_ALLOWED exception - right now 6000 - 2012-06-05
    public const int MAX_PARTS_IN_QUERY = 1;
    public StringBuilder query;
    bool havePartsToInsert = false;
    int insertedCount = 0;

    public PartsInventories()
    {
        mySql = new MySqlDb();
    }

    public void Init(int usersCompanyId, string mailId,
            string appendDate, bool toInsertPrices, string fileId)
    {
        // init query string and shared query variables here
        insertedCount = 0;
        query = new StringBuilder(GetQueryString());
    }

    private string GetQueryString()
    {
        return @"INSERT INTO  parts_inventories (part_number,base_part_number,
            date_code,quantity,price,currency_types_id,delivery,rohs,parts_pkg_type_id,parts_mfg_id,
            users_company_id,notes,in_stock,mail_id,append_date,file_id,ad_price) VALUES ";
    }

    private void InsertPart(ParsedInformation part, bool toInsertPrices)
    {
        // assign all specific query variables here
         query.AppendFormat("({0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},'{14}',{15},{16}),",
                    PartNumber, BasePartNumber, DateCode, Quantity, Price, CurrencyTypesId, Delivery,
                    Rohs, PartsPkgTypeId, PartsMfgId, UsersCompanyId, Notes, InStock, MailId, AppendDate, FileId, adPrice);
    }

    public void InsertPart(ParsedInformation part)
    {
        InsertPart(part, toInsertPrices);
        insertedCount++;
        if (insertedCount % MAX_PARTS_IN_QUERY == 0)
        {
            Insert();
            query = new StringBuilder(GetQueryString());
        }                
    }

    public void Insert()
    {
        if (!havePartsToInsert) return;

        query.Remove(query.Length - 1, 1);

        query.Append(@" ON DUPLICATE KEY UPDATE part_number = VALUES(part_number), date_code = VALUES(date_code),
        quantity = VALUES(quantity), price = VALUES(price), currency_types_id = VALUES(currency_types_id),
        delivery = VALUES(delivery),rohs = VALUES(rohs), parts_pkg_type_id = VALUES(parts_pkg_type_id),
        parts_mfg_id = VALUES(parts_mfg_id), notes = VALUES(notes), in_stock = VALUES(in_stock),
        mail_id = VALUES(mail_id), append_date = VALUES(append_date), sent_rfq = NULL, from_website = NULL, from_lti = NULL, 
        file_id = VALUES(file_id), ad_price = VALUES(ad_price);");

        try
        {
            logger.DebugFormat("Inserted/Updated {0} parts.", mySql.ExecuteInsert(query.ToString()));
            havePartsToInsert = false;
        }
        catch
        {
            logger.Debug("problem inserting");
            havePartsToInsert = false;
            throw;
        }
    }
}

每个线程都是一个类,并从创建和调用线程的类接收列表。

class ThreadInserter 
{
    ManualResetEvent doneEvent;
    PartsInventories partsInventories;
    public ThreadSafeInserter(List<ParsedInformation> allParts, ManualResetEvent doneEvent, string mailId, int usersCompanyId,
            string appendDate, bool toInsertPrices, bool hasStockInBody, string fileId)
    {
        this.doneEvent = doneEvent;
        partsInventories = new PartsInventories();
    }

    private void InsertAllParts(int threadIndex)
    {
        partsInventories.Init(usersCompanyId, mailId, appendDate, toInsertPrices, fileId);

        if (allParts != null)
        {
            foreach (ParsedInformation part in allParts)
            {
                // another thread has thrown an exception so aborting all threads
                // set from the main invoking the threadcallback 
                if (doneEvent.WaitOne(0)) 
                {
                    logger.Warn("Thread aborted.");
                    return; 
                }
                partsInventories.InsertPart(part);
            }
        }
        partsInventories.Insert(); 
        doneEvent.Set();
    }
}

0 个答案:

没有答案