Как получить доступ к MySQL из нескольких потоков одновременно - PullRequest
21 голосов
/ 21 сентября 2009

Мы проводим небольшой тест MySQL, где хотим посмотреть, как он работает с нашими данными.

Часть этого теста состоит в том, чтобы увидеть, как он работает, когда несколько параллельных потоков забивают сервер различными запросами.

Документация MySQL (5.0) не совсем понятна для многопоточных клиентов. Я должен указать, что я делаю ссылку на поточно-безопасную библиотеку (libmysqlclient_r.so)

Я использую подготовленные операторы и делаю как чтение (SELECT), так и запись (UPDATE, INSERT, DELETE).

  • Должен ли я открыть одно соединение на поток? И если так: как мне вообще это сделать .. похоже mysql_real_connect() возвращает исходный дескриптор БД, который я получил, когда позвонил mysql_init())
  • Если нет: как я могу убедиться, что результаты и методы, такие как mysql_affected_rows, возвращают правильное значение, а не сталкиваются с вызовами других потоков (мьютекс / блокировки могут работать, но это не так)

Ответы [ 4 ]

26 голосов
/ 22 сентября 2009

Как сопровождающий довольно большого C-приложения, которое выполняет вызовы MySQL из нескольких потоков, я могу сказать, что у меня не было проблем с простым установлением нового соединения в каждом потоке. Некоторые замечания, с которыми я столкнулся:

  • Редактировать: кажется, что этот пункт относится только к версиям <5.5; см. <a href="http://dev.mysql.com/doc/refman/5.7/en/c-api-threaded-clients.html" rel="noreferrer"> эту страницу для соответствующей версии : Как вы уже сказали, ссылка на 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), и это будет работать так, как вы ожидаете.

Мне кажется, это меньше работы, чем создание пула соединений.

6 голосов
/ 21 сентября 2009

Вы можете создать пул соединений. Каждый поток, которому требуется соединение, может запросить бесплатный пул из пула. Если доступного соединения нет, вы либо блокируете, либо увеличиваете пул, добавляя к нему новое соединение.

Здесь есть статья здесь , описывающая плюсы и минусы пула соединений (хотя она основана на Java)

Edit: вот SO вопрос / ответ о пулах соединений в C

Edit2: вот ссылка на образец Пул соединений для MySQL , написанный на C ++. (вам, вероятно, следует игнорировать операторы goto, когда вы реализуете свои собственные.)

1 голос
/ 21 сентября 2009

Мне кажется из документов MySQL, что любая конкретная структура MYSQL может быть использована в потоке без каких-либо трудностей - одновременное использование одинаковой структуры MYSQL в разных потоках однозначно даст вам крайне непредсказуемые результаты, поскольку состояние хранится в соединении MYSQL.

Таким образом, либо создайте соединение для каждого потока, либо используйте пул соединений, как предложено выше, и защитите доступ к этому пулу (т. Е. Резервируя или освобождая соединение), используя какой-то Mutex.

0 голосов
/ 21 сентября 2009

Многопоточные клиенты MySQL в C

В нем говорится, что mysql_real_connect () не является потокобезопасным по умолчанию. Клиентская библиотека должна быть скомпилирована для многопоточного доступа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...