Обновить запрос с помощью выбора и блокировки строк - PullRequest
2 голосов
/ 20 июля 2011
update mytable set node_index=0 where id in (
        SELECT 
            id
         FROM mytable
         WHERE 
            rownum<=10 and PROCS_DT is null  
         order by CRET_DT,PRTY desc) 

Я получил этот запрос как часть предыдущего ответа на мой вопрос. Теперь, как заблокировать строки в запросе выбора, чтобы убедиться, что никакой другой поток не записывает мое обновление.

Ответы [ 2 ]

5 голосов
/ 20 июля 2011

Мне не ясно, что у вас есть проблема, которую вы, кажется, думаете, что у вас есть.

Обновление строки в таблице по сути устанавливает блокировку уровня строки в этой строке. Никакой другой сеанс не может обновить эту строку, пока вы не снимите блокировку, завершив транзакцию фиксацией или откатом. После завершения транзакции другие сеансы могут перезаписать ваше обновление. Нет необходимости или пользы для блокировки строк в SELECT.

Если вы пытаетесь написать свое приложение, чтобы избежать потерянных обновлений (то есть вы хотите, чтобы другой сеанс не обновлял те же строки, которые вы сделали после совершения транзакции, не показывая другому пользователю ваши обновленные данные в первую очередь), вашему приложению потребуется реализовать какую-то дополнительную блокировку. Наиболее эффективным было бы реализовать оптимистическую блокировку с использованием некоторого столбца LAST_UPDATE_TIMESTAMP в таблице. Предполагая, что вы добавили этот столбец в таблицу, если у него его еще нет, вы будете выбирать LAST_UPDATE_TIMESTAMP всякий раз, когда запрашиваете данные для представления пользователю, и вы указали бы LAST_UPDATE_TIMESTAMP в своем UPDATE. Если ваш UPDATE обновил ровно 1 строку, вы знаете, что никто не изменил данные с тех пор, как вы их запросили. Если бы ваши UPDATE обновили 0 строк, вы бы знали, что данные изменились, так как вы запросили их, и ваше приложение должно будет предпринять соответствующие действия (то есть запрос данных, повторное представление их пользователю, запрос пользователя сохранить ли внесенные изменения и т. д.).

Однако в вашем запросе есть другая проблема. SELECT утверждение почти наверняка не делает то, что вы думаете (или намереваетесь) сделать. Этот запрос получает произвольные 10 строк из MYTABLE, где PROCS_DT равен NULL, а затем упорядочивает эти произвольные 10 строк.

         SELECT 
            id
         FROM mytable
         WHERE 
            rownum<=10 and PROCS_DT is null  
         order by CRET_DT,PRTY desc

Предполагая, что вы действительно хотите получить "10 лучших" результатов, вам нужно будет сделать ORDER BY в подзапросе перед применением предиката ROWNUM, то есть

         SELECT 
            id
         FROM (SELECT *
                 FROM mytable
                WHERE procs_dt IS NULL
                ORDER BY cret_dt, prty desc)
         WHERE 
            rownum<=10 

Или вы можете использовать аналитическую функцию, т.е.

         SELECT 
            id
         FROM (SELECT m.*,
                      rank() over (ORDER BY cret_dt, prty desc) rnk
                 FROM mytable m
                WHERE procs_dt IS NULL)
         WHERE 
            rnk<=10 
3 голосов
/ 20 июля 2011

Чтобы заблокировать строки в Oracle, вы можете сделать:

SELECT *
  FROM table1
WHERE some_condition
FOR UPDATE OF table1;

Гораздо лучше просто заблокировать нужные вам строки вместо всей таблицы.

См. Здесь: http://www.techonthenet.com/oracle/cursors/for_update.php

Но в целом, если вы делаете UPDATE с одним оператором, вам не нужно беспокоиться о блокировке таблицы или даже строк. Когда вам нужно использовать несколько операторов, вам нужно блокировать строки.

Сценарий, в котором вам нужно будет использовать эту функцию, будет в системе бронирования. Рассмотрим этот пример:

1. Execute SELECT to find out if room XYZ is available for a reservation on date X.
2. The room is available. Execute UPDATE query to book the room.

Вы видите здесь потенциальную проблему? Если между шагами 1 и 2 комната забронирована другой транзакцией, то, когда мы достигаем шага 2, мы действуем в предположении, которое больше не действует, а именно, что комната доступна.

Однако, если на шаге 1 вместо этого мы используем инструкцию SELECT FOR UPDATE, мы гарантируем, что никакая другая транзакция не сможет заблокировать эту строку, поэтому, когда мы перейдем к UPDATE строки, мы знаем, что это безопасно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...