Как обращаться к MySQL из нескольких потоков одновременно
Мы делаем небольшой тест MySQL, где хотим видеть, как он работает для наших данных.
Часть этого теста заключается в том, чтобы увидеть, как он работает, когда несколько параллельных потоков забивают сервер с различными запросами.
Документация по MySQL (5.0) не совсем понятна для многопоточных клиентов. Я должен указать, что я связываюсь с библиотекой, защищенной потоком (libmysqlclient_r.so
)
Я использую подготовленные инструкции и читаю (SELECT) и записываю (UPDATE, INSERT, DELETE).
- Должен ли я открыть одно соединение на поток? И если да: как это сделать... кажется, что
mysql_real_connect()
возвращает исходный дескриптор БД, который я получил, когда вызывал mysql_init()
)
- Если нет: как я могу убедиться, что результаты и методы, такие как
mysql_affected_rows
, возвращают правильное значение вместо того, чтобы сталкиваться с другими потоковыми вызовами (mutex/locks могут работать, но он чувствует себя не так).
Ответы
Ответ 1
Как поддерживающий довольно большое приложение C, которое делает запросы MySQL из нескольких потоков, я могу сказать, что у меня не было проблем с простое создание нового соединения в каждом потоке. Некоторые оговорки, которые я встретил:
- Изменить: похоже, эта пуля применима только к версиям < 5,5; см. эту страницу для вашей соответствующей версии: Как вы уже сказали, ссылку на
libmysqlclient_r
.
- Вызовите
mysql_library_init()
(один раз, от main()
). Прочтите документы об использовании в многопоточных средах, чтобы узнать, почему это необходимо.
- Создайте новую структуру
MYSQL
, используя mysql_init()
в каждом потоке. У этого есть побочный эффект вызова mysql_thread_init()
для вас. mysql_real_connect()
, как обычно, внутри каждого потока, с его структурой MYSQL, специфичной для потока.
- Если вы создаете/уничтожаете много потоков, вы захотите использовать
mysql_thread_end()
в конце каждого потока (и mysql_library_end()
в конце main()
). В любом случае, это хорошая практика.
В принципе, не разделяйте структуры MYSQL
или что-либо, созданное специально для этой структуры (т.е. MYSQL_STMT
s), и оно будет работать так, как вы ожидаете.
Это похоже на работу меньше, чем создание пула соединений.
Ответ 2
Вы можете создать пул соединений. Каждый поток, которому требуется соединение, может запрашивать у пула свободный. Если соединение отсутствует, вы либо блокируете, либо увеличиваете пул, добавляя к нему новое соединение.
Здесь есть статья описывающая про и минусы пула соединений (хотя он основан на Java)
Изменить: здесь SO-вопрос/ответ о пулах соединений в C
Edit2: Здесь ссылка на образец Пул соединений для MySQL, написанный на С++. (вы, вероятно, должны игнорировать утверждения goto, когда вы реализуете свои собственные.)
Ответ 3
Мне кажется, что из mySQL Docs любая структура MYSQL может быть использована в потоке без труда - использование одной и той же структуры MYSQL в разных потоках одновременно явно даст вам крайне непредсказуемые результаты, поскольку состояние хранится в MYSQL соединение.
Таким образом, либо создайте соединение для каждого потока, либо используйте пул соединений, как было предложено выше, и защитите доступ к этому пулу (т.е. резервирование или освобождение соединения) с использованием какого-либо Mutex.
Ответ 4
MySQL Threaded Clients в C
В нем указано, что mysql_real_connect() по умолчанию не является потокобезопасным. Библиотеку клиента необходимо скомпилировать для поточного доступа.