2014-09-21 2 views
0

Допустим, у меня есть следующая Хранимая процедура в PostgreSQL. (Обратите внимание, что это не реальный код. Я знаю, что это может быть сделано в другой, и лучший способ, это просто пример, чтобы проиллюстрировать мой вопрос)Являются ли функции PostgreSQL атомарными? (Генерация ID)

CREATE FUNCTION testFunction() RETURNS integer AS $$ 
DECLARE iNewID integer; 
BEGIN 
    SELECT CurrentID INTO iNewID FROM TestTable; // statement 1 

    iNewID := iNewID + 1; 

    UPDATE TestTable SET CurrentID=iNewID; // statement 2 

    RETURN iNewID; 
END; $$ 
LANGUAGE PLPGSQL; 

Допустим, что два пользователя запустить это в почти в то же время. Могут ли они получить одинаковый идентификатор?

Я попытаюсь объяснить другими словами. В коде я прокомментировал два утверждения. Если два пользователя запускают это одновременно. В каком порядке называется утверждение. Могу ли я быть уверен, что это будет выглядеть следующим образом:

  • пользователя Заявление 1
  • пользователя Заявление 2
  • пользователя B Заявление 1
  • пользователя B Заявление 2

Или, может (с тем же идентификатором):

  • Заявление пользователя А 1
  • пользователя B Заявление 1
  • пользователя Заявление 2
  • пользователя B Заявление 2

Я надеюсь, что вы понимаете мой вопрос. Я действительно пытался найти в сети ответ на этот вопрос, но не повезло. Это может быть потому, что у меня нет имени для этого? Как это называется?

Большое спасибо за любую помощь.

ответ

3

Предположим, что два разных пользователя запускают это почти одновременно. Могут ли они получить одинаковый идентификатор?

Да, конечно. Это точно так же, как если бы вы запускали его как два отдельных оператора вне транзакции, делая дополнение в своем приложении.

I wrote about this recently.

Используйте SEQUENCE для обеспечения уникальных идентификаторов. Псевдо-тип SERIAL делает это проще. Обратите внимание, что идентификаторы не гарантируют беспроблемность; это нормально, чтобы иметь идентификаторы типа: 1, 3, 4, 5, 6, 9, 10, 11, 14, .. если транзакции откат, сервер перезапускается и т. д.

Если это проблема для вас, вы хотите, чтобы вместо этого сделать:

SELECT CurrentID INTO iNewID FROM TestTable FOR UPDATE; 
... blah blah ... 

... который будет блокировать строку, так что другие транзакции не могут обновить его до тех пор, ток один не совершает или откат. Это на самом деле может быть упрощена с помощью PostgreSQL конкретных функций в:

UPDATE TestTable 
    SET CurrentID = iNewID 
    RETURNING CurrentID; 

, которые затем можно обернуть в функцию SQL или запустить в PL/PgSQL с RETURN QUERY.

+0

Большое спасибо за ваш ответ и ссылку на отличную статью! ... Я просто использовал пример ID, чтобы проиллюстрировать мою проблему.Это не то, что я пытаюсь сделать в своей реальной работе. Для моей реальной работы невозможно редактировать SQL или использовать «FOR UPDATE». Возможно, я должен посмотреть на SERIALIZABLE транзакции, упомянутые в вашей статье. Что мне не нравится в этом, так это то, что вторая сессия прерывается. Невозможно, чтобы хранимая процедура работала так же, как и один оператор. Итак, если две сессии начинаются в одно и то же время, один из них ждет, пока другой закончит, а затем запустится? – Thomas

Смежные вопросы