mysql 队列 实现并发读

一个 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
scheduleCURRENT_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-运行

最近做项目的时候设计每天定点执行的脚本,所以在这 马克一下,方便查找 

 

  set time_zone = ‘+8:00’;  
    set GLOBAL event_scheduler = 1;  
      
    — 设置该事件使用或所属的数据库base数据库  
    use nitrogenates;  
      
    # 如果原来存在该名字的任务计划则先删除  
    drop event if exists upload_to_sdmp;  
      
    # 设置分隔符为 ‘$$’ ,mysql默认的语句分隔符为 ‘;’ ,这样在后续的
create 到 end 这段代码都会看成是一条语句来执行  
    DELIMITER $$  
    # 创建计划任务,设置第一次执行时间为’2014-07-30
10:00:00’,并且每天执行一次  
    create event upload_to_sdmp   
    on schedule every 1 day starts timestamp ‘2017-01-17 07:16:00’  
    #on schedule every 1 SECOND  
    do  
      
    # 开始该计划任务要做的事  
    begin  
      
      
    — do something 编写你的计划任务要做的事  
      # INSERT test_group(name,project_id) VALUES (“haha”,1);  
      

            # 获取最后一次执行的 Case_ALL,并复制到新ID中
            #更改时间为当前时间
            #将最后一次执行的 Case对应的 ID 变成新ID。
            Insert into execution(name,project_id,test_suite_id)
select name,project_id,test_suite_id from execution WHERE
test_suite_id=3 ORDER BY created_time DESC LIMIT 1;
            UPDATE execution SET created_time=(select
CURRENT_TIMESTAMP) WHERE created_time=”0000-00-00 00:00:00″;
            #UPDATE queue_entry SET execution_id=(SELECT id FROM
execution ORDER BY id DESC LIMIT 1) WHERE execution_id=(select id from
execution WHERE test_suite_id=3 ORDER BY created_time DESC LIMIT
1,1);
            Insert into queue_entry(test_case_id,project_id) select
test_case_id,project_id from queue_entry WHERE execution_id=(select
id from execution WHERE test_suite_id=3 ORDER BY created_time DESC
LIMIT 1,1);
            UPDATE queue_entry SET execution_id=(SELECT id FROM
execution ORDER BY id DESC LIMIT 1) WHERE execution_id=0;

            #获取倒数第二条
            #select id from execution WHERE test_suite_id=3 ORDER BY
created_time DESC LIMIT 1,1;    
            #最新的 ID
            #SELECT id FROM execution ORDER BY id DESC LIMIT 1;

    — 结束计划任务  
    end $$  
      
    # 将语句分割符设置回 ‘;’  
    DELIMITER ;  

最近做项目的时候设计每天定点执行的脚本,所以在这 马克一下,方便查找 set
time_zone = ‘+8:00’; set GLOBAL eve…