mysql选择更新,多线程超时

f1tvaqid  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(466)

我在mysql数据库中有一个表,其中包含一些“准备好的”作业。

  1. CREATE TABLE `ww_jobs_for_update` (
  2. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  3. `status` int(11) NOT NULL,
  4. `inc` int(11) NOT NULL,
  5. PRIMARY KEY (`id`)
  6. )

现在我有了一个c1y多线程应用程序,其中每个线程都进入表并选择一个状态为0(未完成)的作业,执行一些计算并在完成时将状态设置为1。
问题是许多线程将同时获取一个“作业行”,因此必须在数据库中进行一些锁定。
锁定/更新/提交的c
方法如下

  1. connection = "borrow a connection from the pool"
  2. std::unique_ptr<sql::Statement> statement(connection->sql_connection_->createStatement());
  3. connection->sql_connection_->setAutoCommit(false);
  4. //statement->execute("START TRANSACTION");
  5. std::unique_ptr<sql::ResultSet> rs(statement->executeQuery("select id from ww_jobs_for_update where status=0 ORDER BY id LIMIT 1 FOR UPDATE"));
  6. if (rs->next()) {
  7. db_id = rs->getInt64(1);
  8. DEBUG << "Unlock Fetched: " << db_id;
  9. }
  10. rs->close();
  11. std::stringstream ss;
  12. ss << "update ww_jobs_for_update set status=1 where id=" << db_id;
  13. statement->execute(ss.str());
  14. //statement->execute("COMMIT;");
  15. connection->sql_connection_->commit();
  16. "release the connection to the pool();"

但这种方法似乎效率不高。我总是回来
错误代码:1205,sqlstate:hy000。细节:
从很多线程,特别是当负载增加时。
为什么我要拿回这个?最有效的方法是什么,严格的一致性是一个要求。

xyhw6mcr

xyhw6mcr1#

根据我的经验,执行此任务的最佳方法是使用redis队列。锁定表选择。。。因为更新是挂起数据库,当你有一些多线程应用程序运行等。
我建议您安装一个redis,并编写一些脚本来根据表中的数据创建队列,然后重写您的程序以使用redis队列执行任务。redis队列不会为不同的线程提供相同的值,因此您可以获得唯一性,并且数据库中没有锁—因此您的脚本将运行得很快。

e37o9pze

e37o9pze2#

你能缩短你的交易时间吗?这就是我的意思。
“等待”的状态值为0,“完成”的状态值为1。使用状态值2(或-1,或您选择的任何值)表示“正在工作”。
然后,当工作线程从表中获取要执行的作业时,它将执行此操作(伪sql)。

  1. BEGIN TRANSACTION
  2. SELECT id FROM ww_jobs_for_update WHERE status=0 ORDER BY id LIMIT 1 FOR UPDATE
  3. UPDATE ww_jobs_for_update SET status=2 WHERE id = << db_id
  4. COMMIT

现在,您的线程接受了一个作业并释放了事务锁。当作业完成时,您只需这样做来标记它已完成,而不需要任何事务。

  1. UPDATE ww_jobs_for_update SET status=1 WHERE id=" << db_id;

如果可以保证每个工作线程都有一个唯一的标识符,那么有一种更简单的方法来实现这一点 threadId . 放一个 thread 表中具有默认空值的列。然后开始处理作业。

  1. UPDATE ww_jobs_for_update
  2. SET thread = threadId, status = 2
  3. WHERE status = 0 AND threadId IS NULL
  4. ORDER BY id LIMIT 1;
  5. SELECT id FROM ww_jobs_for_update WHERE thread = threadId AND status=2

完成时

  1. UPDATE ww_jobs_for_update
  2. SET thread = NULL, status = 1
  3. WHERE thread = threadId;

因为每个线程都有一个唯一的threadid,而且单个sql update语句本身就是一个小事务,所以您可以不使用任何事务或提交来完成这项工作。
这两种方法都有一个额外的好处,即您可以使用select查询找出哪些作业处于活动状态。这可能会让你处理的工作,从来没有完成的任何原因。

展开查看全部

相关问题