oracle for update实现线程同步取数据

来源:互联网 发布:mfc编程实例pdf 编辑:程序博客网 时间:2024/06/16 13:01

        背景:在电信软件领域,一个软件常常有多个portal,对于话单的处理常常用多个定时任务来处理,那么问题来了,如何保证每个portal的每个定时任务取得话单都是各不相同的呢? 有人会问,为什么不在取数据的Java侧进行同步控制呢,但是问题是多个portal,很明显这不是Java侧的同步能控制的。

        基础:oracle的for update关键字是一个行级排它锁,也就是说for update只会排他锁定相关的行,并不会锁定整个表,在锁定期间,其他线程可以读取,但不能再加其他排它锁了,任何尝试加排它锁的线程都将阻塞等待该锁的释放(注:for update nowait不会等待,直接返回错误)。oracle遇到for update的语句就会自动进入事务(和 update操作是一个效果),我们可以做一个简单的实验,在pl/sql dev中写“select * from TICKET t where t.id = 1 for update;”,执行它会发现左上角出现了事务提交和事务回滚的按钮。

       实现:那么我们同步获取话单数据就可以利用for update加排它锁的特性,来实现同步取数据,实现如下:

create or replace procedure p_sycn_getoneticket(       dt_in_createtime in date,                --createtime       cur_tickets out sys_refcursor         --return cursor) as      --定义数组实体,用于后边接受数据       nstb_ids nstb_numbers_type := new nstb_numbers_type();begin       --取数据       select t.id        bulk collect into nstb_ids         from ticket t       where t.createtime < dt_in_createtime           and  t.status = 1           for update;                          --更新数据状态,避免被其他线程获取到      update ticket t             set t.status = 2       where t.createtime < dt_in_createtime           and  t.status = 1;              --提交,释放update锁       commit;              --将数组数据放入游标,用于返回       open cur_tickets for                  select t1.id, t1.price, t1.des, t1.status, t1.createtime                    from ticket t1, table(cast (nstb_ids as nstb_numbers_type))  t2                 where t1.id = t2.column_value;                 exception         when others then                  rollback;         --返回空游标         open cur_tickets for                   select 'X'                     from dual                    where 1=1;end;
       实现说明:在多线程同时执行该段代码的时候

①线程1先获取到该条记录的行级排它锁,其他线程进入等待状态;

②线程1更新数据状态,并提交,释放锁;

③线程2获取到数据的排它锁,但发现检索发现并不是符合条件的数据,重新检索数据,进而锁定另一部分数据。

如此往复,形成了该段代码对于同一数据行的同步取。

0 0