mysql 队列。实现并发读
来源:互联网 发布:大数据专业名词 编辑:程序博客网 时间:2024/06/05 20:54
队列是常用的数据结构,基本特点就是先入先出,在事务处理等方面都要用到它,有的时候是带有优先级的队列。当队列存在并发访问的时候,比如多线程情况下,就需要锁机制来保证队列中的同一个元素不被多次获取。
一个 MySQL 表可以看作是一个队列,每一行为一个元素。每次查询得到满足某个条件的最前面的一行,并将它从表中删除或者改变它的状态,使得下次查询不会得到它。在没有并发访问的情况下,简单地用 SELECT 得到一行,再用UPDATE(或者DELETE)语句修改之,就可以实现。
SELECT * FROM targets WHERE status='C' LIMIT 1;
UPDATE targets SET status='D' WHERE id='id';
如果有并发访问,在SELECT和UPDATE语句之间可能会存在其他地SELECT查询,导致同一行被取出多次。为了保证在并发情况下仍然能正常工作,一种思路是使用数据库地锁来防止,就像在多线程环境下所做地一样。总之,要是的查询和修改为一个原子操作,不被其它的访问干扰。MySQL 5 支持存储过程,可以用它来实现。
单条 UPDATE 语句应该原子操作的,可以利用这个特性来保证并发访问情况下队列的正常工作。每次取元素时,先用 UPDATE 修改符合条件的第一行,然后再得到该行。可惜 UPDATE 语句没有返回值,重新用普通的SELECT的话又很难找到刚被改过的那条记录。
这里用到一个小技巧:在 UPDATE 时加上 id=LAST_INSERT_ID(id),再用 SELECT LAST_INSERT_ID() 即可得到刚修改的那条记录的id。还有一个问题,当表中不存在符合条件的记录,导致 UPDATE 失败时,LAST_INSERT_ID() 会保留原来地值不变,因而不能区分队列中是否还有元素。
ROW_COUNT() 返回上一个语句影响的行数,把它作为 SELECT 的一个条件,可以帮助解决这个问题。
最后,支持并发访问的完整解决方案为:
UPDATE targets SET status='D', id=LAST_INSERT_ID(id) WHERE status='C' LIMIT 1;
SELECT * FROM targets WHERE ROW_COUNT()>0 and id=LAST_INSERT_ID();
更新:在实现带优先级的队列时这种方法有问题,带有 ORDER BY ... 条件的 UPDATE 语句非常慢,例如:
UPDATE targets SET status='D' WHERE status='C' ORDER BY schedule ASC LIMIT 1;
而单独查询和更新则是很快的:
SELECT id FROM targets WHERE status='C' ORDER BY schedule ASC LIMIT 1;
UPDATE targets SET status='D' WHERE id='id';
原来这是MySQL的Bug-12915,一年多以前提出来的,虽然关闭了,却只解决了部分问题,尚不支持WHERE,见MySQL 5.0.15 的 Changlog。无奈,上面这种巧妙的方法也没有实用价值了。
最后采用了一种折衷方案,如下:
UPDATE targets, (SELECT id FROM targets WHERE status='C' AND schedule<CURRENT_TIMESTAMP ORDER BY schedule ASC LIMIT 1) tmp SET status='D' WHERE targets.id=LAST_INSERT_ID(tmp.id);
SELECT * FROM targets WHERE ROW_COUNT()>0 and id=LAST_INSERT_ID();
- mysql 队列。实现并发读
- mysql 队列 实现并发读
- mysql 队列 实现并发读
- mysql 队列 实现并发读
- 一种可并发读写的队列实现
- 无锁并发队列的实现
- Java阻塞队列SynchronousQueue实现并发
- 高性能并发队列(C++实现)
- FIFO队列并发同步访问 C++ 实现 ~~~
- 并发无锁环形队列的实现
- shell队列实现线程并发控制
- 并发编程-wait,notify实现队列功能
- shell队列实现线程并发控制
- 并发队列
- MYSQL数据库模拟队列实现
- 一种读写可并发进行的队列的实现方法
- Java并发包中的同步队列SynchronousQueue实现原理
- 实现有大小限制的并发阻塞队列
- Codeforces Beta Round #96 (Div. 2) (模拟)
- 数据绑定(四)使用DataContext作为Binding的Source
- Codeforces Beta Round #96 (Div. 2) (DP)
- Eclipse 快捷键 查看方法在那里被调用~
- 如何将数据库的数据导入到csv文件中
- mysql 队列。实现并发读
- Hibernate数据对象的三种状态
- 十八. 和系统运行状况相关的Shell命令:
- C#中结构与类的区别
- Android Jni 学习实战之(一)
- 通过CoA Message让Radius来踢用户下线
- android 少用static全局变量共享数据讨论
- some collected compile error for firefox source on Ubuntu 10.04
- Codeforces Beta Round #95 (Div. 2)