powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Транзакции в процедурах
14 сообщений из 14, страница 1 из 1
Транзакции в процедурах
    #33632867
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте,
Есть такая проблема
Процедура:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
BEGIN
	newid :=  0 ;
	SELECT INTO find_words id FROM words WHERE name=newword;

	IF find_words IS NULL THEN
		INSERT INTO words VALUES("newword");
		SELECT INTO newid currval('public.words_id_seq');
	ELSE
		newid := find_words;
	END IF;

	RETURN newid;
END;
добавляет слово "newword" в таблицу words, если его там нет, и возвращяет его id если оно там есть

На таблице words стоит уникальный индекс на поле name

При выполнении иногда выдаёт ошибку: ERROR: duplicate key violates unique constraint "word_name"

Процедура вызывается из многопоточного приложения.
Может быть так что между Select ... Insert в таблицу добавляется то самое слово, которое мы пытаемся инсертить? И если да, то как с этим бороться ?
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633175
.Guest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
IF find_words IS NULL THEN >> IF NOT FOUND THEN ?
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633198
Funny_Falcon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мало того: слово может вставиться еще до первого select и закомититься после (если уровень сериализации read commited)
Лечить как? Гуру могут предложить правильный вариант, мои предложения:
- или вставку слов осуществлять из одного потока
- или ловить данную ошибку и делать вторую попытку.
Я лично за второй вариант, хотя и первый не плох, если не надо скорость любой ценой (и неизвестно что быстрее, кстати: если на сервере одно ядро, то вставка через одно соединение может быть быстрее).
Умные люди могут подсказать третий.
например
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
BEGIN
   newid :=  0 ;
   BEGIN
	INSERT INTO words VALUES("newword");
	SELECT INTO newid currval('public.words_id_seq');
   EXCEPTION
        WHEN UNIQUE_VIOLATION THEN
	      SELECT INTO find_words id FROM words WHERE name=newword;
   END;
   RETURN newid;
END;
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633344
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Funny_Falcon
- или вставку слов осуществлять из одного потока

не подходит, структура приложения не позволяет

Funny_Falcon
- или ловить данную ошибку и делать вторую попытку.

А что если и вторая попытка обломается ? ;-) Конечно вероятность мала, но всё же.
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633428
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
INSERT INTO words (word) 
SELECT newword
   WHERE 
    (SELECT id FROM words WHERE word = newword) IS NULL;
IF FOUND THEN
     SELECT INTO newid currval('public.words_id_seq');
ELSE 
    SELECT INTO find_words id FROM words WHERE name=newword;
END IF;
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633432
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
токо вместо поля word - name
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633448
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
golden13На таблице words стоит уникальный индекс на поле nameэто кстати приведет к тому, что конкурирующий процесс попросту повиснет на инсерте до закрытия первой записавшей данное значение транзакции, и вернет уже присвоенное той значение (или запишет свое - если та обломается).
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633767
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
4321
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
INSERT INTO words (word) 
SELECT newword
   WHERE 
    (SELECT id FROM words WHERE word = newword) IS NULL;
IF FOUND THEN
     SELECT INTO newid currval('public.words_id_seq');
ELSE 
    SELECT INTO find_words id FROM words WHERE name=newword;
END IF;


А в данном случае разве не может возникнуть ситуации когда между селектом и инсертом в таблицу добавляется то самое слово другим процессом ?
Или здесь так как всё это в рамках инсерта, то блокируется таблица/запись с искомым словом
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33633776
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
торможу.
в данном случае всё ок.
Спасибо, это как раз то что нужно
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33634389
Funny_Falcon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Просто ради интереса: а мой вариант той процедуры прокатил?
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33634484
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
golden13А в данном случае разве не может возникнуть ситуации когда между селектом и инсертом в таблицу добавляется то самое слово другим процессом ?
Или здесь так как всё это в рамках инсерта, то блокируется таблица/запись с искомым словомнет блокировка на вставку тут возникнет из-за уникью (тот случай, когда версионник ведет себя как блокировочник)). и будет держаться вплоть до завершения конкурирующей транзакции. при этом транзакция будет висеть на инсерте дожидаясь чем кончится конкурирующая.
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33634870
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Funny_FalconПросто ради интереса: а мой вариант той процедуры прокатил?
вроде да, хотя основательно я не тестировал :)
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33635550
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не уверен, что я правильно осознал все обсуждавшиеся проблемы, но IMHO было достаточно просто SELECT .. FOR UPDATE.
...
Рейтинг: 0 / 0
Транзакции в процедурах
    #33636118
Funny_Falcon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2ilejn

Не достаточно: если процедура не видит строку, она не сможет пометить её как FOR UPDATE.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Транзакции в процедурах
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]