c # многопоточность и базы данных

2

У меня есть winform с некоторыми дочерними формами. Теперь я получаю доступ к дочерним формам в виде дерева в моей основной форме. Теперь в этом дереве есть список сайтов. Поскольку веб-сайт представляет собой группу страниц, это также показано в дереве. Веб-сайт является моим родителем, а страницы - дочерними.

Когда вы нажимаете на одну из страниц, статистика отображается в дочерней форме. При нажатии на веб-сайт на этом веб-сайте отображается сводка всех страниц. Поскольку у меня может быть много данных, я использую фоновый рабочий, который извлекает статику в фоновом режиме после загрузки древовидного изображения.

Теперь все отлично, пока я не изменю что-то в статистике, и оно автоматически сохраняется в базе данных (sqlserver2008). Затем мой фоновой рабочий создает ошибки, указывающие, что sqlreader закрыт. Поэтому мне интересно, как я могу это решить.

Нужно ли мне обращаться к базе данных по отдельному соединению? Любые другие идеи?

Спасибо

Теги:
multithreading
winforms

5 ответов

4
Лучший ответ

Используете ли вы один и тот же объект подключения к базе данных в нескольких потоках? Это небезопасно. Каждый поток должен иметь свое собственное соединение с базой данных или он должен синхронизировать использование, так что только один поток обращается к объекту соединения с базой данных в любой момент.

  • 0
    Я использую только один фоновый рабочий, и теперь он обращается к одному и тому же объекту подключения к базе данных.
  • 0
    Фоновый рабочий использует поток, а ваш графический интерфейс работает в другом потоке. Если эти два потока используют одно и то же соединение с базой данных, они будут влиять друг на друга. Как я и предлагал, создайте новый объект подключения в вашем потоке, в основном в фоновом обработчике рабочего события.
Показать ещё 2 комментария
1

Похоже, что ваш UPDATE закрывает соединение, и ваш фоновый поток пытается использовать его для запроса. Если im считывает между строками правильно, вы создали объект соединения как член состояния вашей winform, который открывается один раз и, возможно, закрывается после UPDATE (или автоматически пулом соединений). В любом случае вам нужно сделать шаг назад и подумать о том, как вы делаете что-то.

Ваши методы обновления и выбора (надеюсь, в отдельных классах для ваших форм) должны заботиться об открытии и закрытии подключений исключительно, а не в полном объеме (т.е. область действия остается в методах). Пул соединений ADO позаботится об оптимизации соединений для вас.

Я также рекомендую использовать отключенные структуры данных, такие как DataTable и DataSet, а не DataReader, поскольку они поддерживают связь между клиентом и базой данных. Вы можете с радостью обрабатывать и передавать эти структуры, не поддерживая открытое соединение, которое требует DataReader. В идеале вы бы заселяли легкую структуру объектов, а не слишком часто пропускали DataSet, так как она несла некоторые издержки памяти - есть еще несколько причин для этого, например. типа безопасности.

Нет ничего плохого в вызове метода, который выполняет запросы по нескольким потокам, пока область действия ограничена этим методом. Например:

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

Вы можете с радостью вызвать вышеупомянутый метод из многих потоков одновременно, и он должен работать. Я работал над приложениями, сильно использующими threadpool, которые выполняли в некоторых случаях десятки запросов одновременно без какого-либо негативного эффекта. Там, где это происходит, я бы рекомендовал установить максимальный размер для пула соединений ado.net, поскольку он может расти довольно большим, если оставить его без охраны (обычно для этого типа атрибута строки соединения используется "Max Pool Size = n" ). Ado.net будет маршировать соединения от вашего имени, так что есть много сантехники, чтобы использовать в рамках здесь.

0

Если вы пытаетесь использовать один и тот же SqlConnection для нескольких потоков одновременно, это, безусловно, приведет к непредсказуемым результатам. Создание соединения для каждого потока проще всего, или вы можете использовать некоторую форму синхронизации, если вы действительно хотите использовать одно соединение. Это имело бы смысл только в том случае, если ваши рабочие потоки выполняют значительную работу помимо доступа к базе данных.

  • 0
    помимо получения данных из базы данных это также делает некоторые статистические вычисления на извлеченных данных
0

Если вы используете одну и ту же строку соединения, вы можете открыть несколько объектов SqlConenction/SqlCommand/SqlDataReader, и они будут поступать из пула соединений. Нет причин, по которым вы не можете иметь несколько подключений к одной и той же базе данных! Вы можете прочитать дополнительную информацию в Пул соединений SQL Server (ADO.NET).

0

Я бы предположил, что событие навигации запускает новый запрос базы данных с использованием существующего sqlcommand. Можете ли вы опубликовать фрагмент кода?

  • 0
    да, это то, что происходит. Поэтому мне интересно, если я должен использовать второй вызов с отдельной командой sql. не могу опубликовать фрагмент кода :( из-за политики компании

Ещё вопросы

Сообщество Overcoder
Наверх
Меню