如何同时从多个线程访问 MySQL

Posted

技术标签:

【中文标题】如何同时从多个线程访问 MySQL【英文标题】:How to access MySQL from multiple threads concurrently 【发布时间】:2010-11-30 02:57:57 【问题描述】:

我们正在做一个 mysql 的小型基准测试,我们想看看它对我们的数据的执行情况。

该测试的一部分是查看当多个并发线程通过各种查询冲击服务器时它是如何工作的。

MySQL documentation (5.0) 并不清楚多线程客户端。我应该指出,我确实链接到线程安全库 (libmysqlclient_r.so)

我正在使用准备好的语句并同时执行读取 (SELECT) 和写入 (UPDATE、INSERT、DELETE)。

我应该为每个线程打开一个连接吗?如果是这样:我该怎么做.. 似乎mysql_real_connect() 返回了我调用mysql_init() 时得到的原始数据库句柄) 如果不是:如何确保结果和方法(例如 mysql_affected_rows)返回正确的值,而不是与其他线程的调用发生冲突(互斥锁/锁可以工作,但感觉不对)

【问题讨论】:

【参考方案1】:

作为一个从多个线程调用 MySQL 的相当大的 C 应用程序的维护者,我可以说我在每个线程中简单地建立一个新连接没有任何问题。我遇到的一些警告:

编辑:似乎此项目符号仅适用于 this page for your appropriate version:就像你说你已经在做的那样,链接到libmysqlclient_r。 致电mysql_library_init()(一次,来自main())。阅读有关在多线程环境中使用的文档,了解其必要性。 在每个线程中使用mysql_init() 创建一个新的MYSQL 结构。这具有为您调用mysql_thread_init() 的副作用。 mysql_real_connect() 像往常一样在每个线程中,具有线程特定的 MYSQL 结构。 如果您要创建/销毁大量线程,则需要在每个线程的末尾使用mysql_thread_end()(并在main() 的末尾使用mysql_library_end())。无论如何,这是一种很好的做法。

基本上,不要共享 MYSQL 结构或为该结构创建的任何特定内容(即 MYSQL_STMTs),它会按您的预期工作。

这似乎比为我建立一个连接池要少。

【讨论】:

这正是我需要的答案。我没有意识到我必须在每个线程中调用 mysql_init ——我只是在 main() 中调用过一次。谢谢 @chazomaticus,您通常会使用多少线程以及打开多少连接?这是否适用于大量线程/连接?如果您有很多线程(100 到 1000),但不希望打开 1000 个连接的开销(您可能无权访问,因为 max_connections 的默认值通常设置为 100),则连接池非常有用。如果您的线程数量较少,那么您的方法将起作用。为我展示代码示例 +1。 由于 Isak 试图对 DB 施加压力,因此尽可能多的线程。我已经运行了 ~1000 次没有问题(如果所有线程都发出查询,那么它们的大部分时间都在poll() 空闲,所以它不像你想象的那样占用大量 CPU,尽管它可以吃掉一大块内存)。你说得对,max_connections 默认限制在 100,所以为了最大压力,根据需要提高。 我在 mysql 5.6.11 上看不到 libmysqlclient_r。在文档中也找不到任何多线程信息 看起来从 5.5 开始,他们停止在库的线程安全/不安全版本之间进行拆分。 (很好摆脱。)参见例如dev.mysql.com/doc/refman/5.6/en/c-api-threaded-clients.html 获取有关 5.6 上的多线程的文档。【参考方案2】:

从 mySQL 文档中我可以清楚地看到,任何特定的 MYSQL 结构都可以毫无困难地在线程中使用 - 同时在不同线程中使用 same MYSQL 结构显然会给您带来极其不可预测的结果因为状态存储在 MYSQL 连接中。

因此,要么为每个线程创建一个连接,要么使用上面建议的连接池,并使用某种互斥锁保护对该池的访问(即保留或释放连接)。

【讨论】:

这就是我所怀疑的......只需要弄清楚如何建立多个连接......现在无法让它工作 从来没有遇到过这个问题,但我通常不使用这些库。在我看来,您应该能够分配单独的 MYSQL 结构并初始化并连接每个结构。【参考方案3】:

您可以创建一个连接池。每个需要连接的线程都可以从池中请求一个空闲的。如果没有可用的连接,则您要么阻止,要么通过向其添加新连接来扩大池。

有一篇文章here 描述了连接池的优缺点(虽然它是基于 java 的)

编辑:这是一个关于connection pools in C的问题/答案

Edit2:这是一个用 C++ 编写的示例Connection Pool for MySQL 的链接。 (当你实现自己的时候,你可能应该忽略 goto 语句。)

【讨论】:

好答案..谢谢。但是我仍然无法打开多个连接,并且您链接到的示例缺少那段代码。我给了你一个 +1,但我不想接受它(还),因为它不能解决我的问题打开多个连接的问题【参考方案4】:

MySQL Threaded Clients in C

它指出 mysql_real_connect() 默认情况下不是线程安全的。需要为线程访问编译客户端库。

【讨论】:

我正在使用 libmysqlclient_r 库,所以我假设它已经编译了所有线程安全的东西。为了确定,我会在产生线程之前尝试做所有连接的东西,看看是否有帮助

以上是关于如何同时从多个线程访问 MySQL的主要内容,如果未能解决你的问题,请参考以下文章

MySQL: 19 生产经验:如何通过多个Buffer Pool来优化数据库的并发性能

多个线程(并行测试用例)如何使用Java(Selenium)设置中的Apache POI同时访问同一个excel文件?

Servlet容器如何同时来处理多个请求

多个线程(并行测试用例)如何在 Java(Selenium)设置中使用 Apache POI 同时访问同一个 excel 文件?

Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行

如果我同时(从多个线程)写入java.util.HashMap会发生什么最糟糕的事情?