Скажем, если у меня есть следующее:
create table jobs
(
staff_id number,
job_name varchar2(1000) not null,
start_date date not null,
end_date date not null
);
Это просто таблица с указанием различных рабочих мест персонала.
Теперь сотрудники могут выполнять только одну работу за раз, поэтому я вставляю задания, используя следующую инструкцию PL / SQL. Если найдено конфликтующее задание, оно не добавляется (вероятно, я должен сообщить об ошибке здесь, но для этого упрощенного примера я игнорирую это):
create or replace procedure add_job
(
p_staff_id number,
p_job_name varchar2,
p_start_date date,
p_end_date date
)
as
begin
insert into jobs
(
select p_staff_id, p_job_name, p_start_date, p_end_date from dual
where not exists
(
select 1 from jobs
where staff_id = p_staff_id
and (end_date > p_start_date)
and (start_date < p_end_date)
)
);
end;
Проблема в том, что, если я добавлю две разные работы в две разные сессии, а затем зафиксирую, я могу удвоить количество заказов. то есть следующее:
-- Session 1:
add_job(1, 'Help Alice', to_date('2011/08/21 11:00:00', 'YYYY/MM/DD HH24/MI/SS'), to_date('2011/08/21 13:00:00', 'YYYY/MM/DD HH24/MI/SS'));
-- Session 2:
add_job(1, 'Help Bob', to_date('2011/08/21 12:00:00', 'YYYY/MM/DD HH24/MI/SS'), to_date('2011/08/21 14:00:00', 'YYYY/MM/DD HH24/MI/SS'));
-- Session 1:
commit;
-- Session 2:
commit;
Выше, staff_id
1 будет забронирован дважды с 12:00 до 13:00.
Похоже, что добавление в начало моей процедуры:
lock table jobs in exclusive mode;
сделал трюк, я чувствую, что это слишком широкий замок. Есть ли способ заставить оракула сделать что-то более тонкое. Я бы предпочел не копаться с dbms_lock
, если это возможно. Эта страница намекнула select ... for update
, но это не дало подробностей.
Можно ли предотвратить двойное бронирование без полной блокировки таблицы или dbms_lock
блокировки? (Я использую Oracle 10g, если это имеет значение).