我在mysql数据库中有一个表,其中包含一些“准备好的”作业。
CREATE TABLE `ww_jobs_for_update` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`status` int(11) NOT NULL,
`inc` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
现在我有了一个c1y多线程应用程序,其中每个线程都进入表并选择一个状态为0(未完成)的作业,执行一些计算并在完成时将状态设置为1。
问题是许多线程将同时获取一个“作业行”,因此必须在数据库中进行一些锁定。
锁定/更新/提交的c方法如下
connection = "borrow a connection from the pool"
std::unique_ptr<sql::Statement> statement(connection->sql_connection_->createStatement());
connection->sql_connection_->setAutoCommit(false);
//statement->execute("START TRANSACTION");
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"));
if (rs->next()) {
db_id = rs->getInt64(1);
DEBUG << "Unlock Fetched: " << db_id;
}
rs->close();
std::stringstream ss;
ss << "update ww_jobs_for_update set status=1 where id=" << db_id;
statement->execute(ss.str());
//statement->execute("COMMIT;");
connection->sql_connection_->commit();
"release the connection to the pool();"
但这种方法似乎效率不高。我总是回来
错误代码:1205,sqlstate:hy000。细节:
从很多线程,特别是当负载增加时。
为什么我要拿回这个?最有效的方法是什么,严格的一致性是一个要求。
2条答案
按热度按时间xyhw6mcr1#
根据我的经验,执行此任务的最佳方法是使用redis队列。锁定表选择。。。因为更新是挂起数据库,当你有一些多线程应用程序运行等。
我建议您安装一个redis,并编写一些脚本来根据表中的数据创建队列,然后重写您的程序以使用redis队列执行任务。redis队列不会为不同的线程提供相同的值,因此您可以获得唯一性,并且数据库中没有锁—因此您的脚本将运行得很快。
e37o9pze2#
你能缩短你的交易时间吗?这就是我的意思。
“等待”的状态值为0,“完成”的状态值为1。使用状态值2(或-1,或您选择的任何值)表示“正在工作”。
然后,当工作线程从表中获取要执行的作业时,它将执行此操作(伪sql)。
现在,您的线程接受了一个作业并释放了事务锁。当作业完成时,您只需这样做来标记它已完成,而不需要任何事务。
如果可以保证每个工作线程都有一个唯一的标识符,那么有一种更简单的方法来实现这一点
threadId
. 放一个thread
表中具有默认空值的列。然后开始处理作业。完成时
因为每个线程都有一个唯一的threadid,而且单个sql update语句本身就是一个小事务,所以您可以不使用任何事务或提交来完成这项工作。
这两种方法都有一个额外的好处,即您可以使用select查询找出哪些作业处于活动状态。这可能会让你处理的工作,从来没有完成的任何原因。