如何在Oracle中同步线程?
我有以下程序如何在Oracle中同步线程?,oracle,plsql,Oracle,Plsql,我有以下程序 procedure MyProc is n number; begin -- Query A select count(*) into n from SomeTable where Column1 = 0; if n = 0 then insert into SomeTable (Column1, Column2) values (0, 'some data');
procedure MyProc is
n number;
begin
-- Query A
select count(*) into n from SomeTable where Column1 = 0;
if n = 0 then
insert into SomeTable (Column1, Column2) values (0, 'some data');
else
update SomeTable set Column2 = 'some other data' where Column1 = 0;
end if;
commit;
end;
此过程由多个线程中的多个作业运行:
for i in 1..10
loop
Jobname := dbms_scheduler.generate_job_name('JobName');
JobAction := 'begin MyProc; end;';
dbms_scheduler.create_job(job_name => Jobname, job_type => 'PLSQL_BLOCK', job_action => JobAction, enabled => true);
end loop;
目标是在表SomeTable中只创建一行,所有其他作业将更新同一行
当所有作业完成时,我注意到有时会创建几行而不是一行
我知道每当执行查询A时,由于行锁,它将只看到在查询开始之前提交的表中的行。。。因此,其他一些工作没有看到变化
请问有没有办法解决这个问题
在.Net中有一个监视的概念。输入和监视。退出,使所有其他线程等待资源释放
有人能帮忙吗
谢谢您应该看看事务隔离级别。关键是哪个数据将恢复运行select计数的第一个查询。如果您没有为事务指定隔离级别,则默认情况下为readcommitted,这允许使用幻影。读取提交事务隔离级别是Oracle的默认级别。使用此设置,每个查询只能看到查询开始前提交的数据,而不能看到事务开始前提交的数据。Oracle查询不会读取脏数据或未提交的数据但是,它不会阻止其他事务修改查询读取的数据。因此,其他事务可能会在执行查询之间更改数据。任何多次执行给定查询的事务都可能经历不可重复的读取或幻影 另一个选项是可序列化的。分布式事务不支持此事务隔离级别使用可序列化事务隔离级别,查询只能访问事务开始时提交的数据以及事务本身通过插入、更新和删除所做的数据 想象一下这种情况
- 作业1进入并执行查询。假设它得到0,因此通过if插入输入。然后插入一行
- 作业2几乎同时进入,如果作业1尚未提交,则计数器为0
- 作业3几乎与作业2同时进入,如果作业1尚未提交,则计数器为0
在您的特定情况下,可能有一种解决方案是使用光标进行select using select for UPDATE。它将锁定受光标影响的行。在光标关闭之前,该行不会被释放。您可以使用dbms\u锁。大概是这样的:
procedure MyProc is
n number;
h varchar2(200);
r number;
begin
-- Query A
dbms_lock.allocate_unique('MyLock', h);
r := dbms_lock.request(h, dbms_lock.x_mode);
select count(*) into n from SomeTable where Column1 = 0;
if n = 0 then
insert into SomeTable (Column1, Column2) values (0, 'some data');
else
update SomeTable set Column2 = 'some other data' where Column1 = 0;
end if;
commit;
dbms_lock.release(h);
end;
@Thomas Carton,要使用DBMS_锁,dba必须将包的执行权限授予拥有该过程的用户。该过程在默认情况下是不可访问的,必须显式地授予。这正是我想要的。很好!谢谢,很好。也许我应该提到,您应该检查来自
dbms\u lock.request的返回值是否不等于0。请参阅可能返回值的文档:您的方法在一致性方面存在问题:每个查询和dml都会看到不同SCN上的数据,因此我建议您避免使用PL/SQL,只需使用bulkmerge
语句即可实现所需