简体   繁体   中英

c# threading and databases

I've got a winform with some child forms on it. Now I'm accessing the child forms by a treeview in my main form. Now in that treeview is a list of websites. Since a website is actually a group of pages, this is also shown in the tree. Website is my parent and the pages are the childs.

When you click on one of the pages the statistics are shown in a child form. When clicked on a website a summary of all pages is shown of that website. Since this can have a lot of data I'm using a background worker that fetches the statics in the background after the treeview is loaded.

Now all fine until I'm changing something in the statistics and it saves automatically into the database (sqlserver2008). Then my backgroundworker generates errors saying the sqlreader is closed. So I'm wondering how I can solve this.

Do I have to access the database on a separate connection? Any other ideas?

Thanks

Are you using the same database connection object on several threads? That's not safe. Every thread must have its own database connection, or it must synchronize the usage so that only one thread accesses the database connection object at any given moment.

It sounds like your UPDATE is closing the connection and your background thread is attempting to use it to query. If im reading between the lines correctly, you have created a connection object as a stateful member of your winform which is being opened once and possibly being closed after an UPDATE (or automatically by the connection pool). Either way you need to take a step back here and think about how your doing things.

Your update and select methods (hopefully in separate classes to your forms) should take care of opening and closing connections exclusively rather than in a statefull way (ie the scope of the connection remains in the methods). The ADO connection pool will take care of optimising connections for you.

I also recommend you use disconnected data structures such as DataTable and DataSet rather than DataReader as these keep the connection footprint between the client and the database light. You can happily process and pass around these structures without maintaining an open connection which DataReader requires. Ideally you would populate a light-weight object structure rather than passing DataSet around too much as it does carry some memory overhead - there are a bunch of other reasons for this too eg type safety.

There is nothing wrong with calling a method which executes queries on multiple threads as long as the scope of the connection is limited to the method. For example:

public static DataSet GetWebStatsData()
{
    DataSet StatsData = new DataSet();
    using (OleDbConnection conn = new OleDbConnection(ConnString))
    {
        using (OleDbCommand cm = new OleDbCommand(GetDataProcedure))
        {
            using (OleDbDataAdapter adap = new OleDbDataAdapter(cm))
            {
                cm.Connection = conn;
                conn.Open();
                adap.Fill(StatsData);
                conn.Close();
            }
        }
    }
    return StatsData;
}

You can happily call the above method from many threads simultaneously and it should work. I have worked on applications making heavy use of the threadpool executing in some cases scores of queries simultaneously with no ill effect. Where this is happening i would recommend setting a maximum size to the ado.net connection pool as it can grow quite large if left un-guarded (there is typically a connection string attribute for this like 'Max Pool Size=n'). Ado.net will marshal the connections on your behalf so there is a lot of plumbing to leverage in the framework here.

I would guess that the navigation event is firing off a new database request using an existing sqlcommand. Can you post up a code snip?

If you're using the same connection string you can open multiple SqlConenction/SqlCommand/SqlDataReader objects and they'll come from the connection pool. There is no reason you can't have multiple connections to the same database! You can read some more information at SQL Server Connection Pooling (ADO.NET) .

If you're trying to use the same SqlConnection on multiple threads at the same time, that will definitely produce unpredictable results. Creating a connection for each thread is easiest, or you could use some form of synchronization if you really want to share a single connection. That would only make sense if your worker threads are doing a significant amount of work besides database access though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM