powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Транзакции и UNIQUE
7 сообщений из 7, страница 1 из 1
Транзакции и UNIQUE
    #34760619
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть такая фукция:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
CREATE OR REPLACE FUNCTION add_one_word(newword character varying)
  RETURNS character varying AS
$BODY$
DECLARE
	find_words INTEGER;
	newid INTEGER;
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;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

Структура таблицы words:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE words
(
  name character varying( 255 ) NOT NULL,
  id serial NOT NULL
) 
WITH OIDS;

CREATE UNIQUE INDEX word_name
  ON words
  USING btree
  (name);

При массовых паралелных вызовах SELECT * FROM add_one_word("ляляля")
переодически возникают ошибки "Повторный ключ нарушает констрейнт UNIQUE word_name..."
Как с этим бороться не подскажете ?
Вроде же процедура выпоняется в рамках одной транзакции и по идее ошибок возникать не должно
Или я туплю?
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760735
Фотография pamir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
golden13Или я туплю?Именно так.

Представьте. Вы выполняете

Код: plaintext
1.
2.
	newid :=  0 ;
	SELECT INTO find_words id FROM words WHERE name=newword;
Ничего не находите. В это время другая транзакция вызывает эту же функцию с тем же параметром. Тоже ничего не находит. Обе пытаются вставить. Кто первый закоммитился - молодец, второй получит ошибку. Пересматривайте логику функции
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760773
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
+1. А задача есть и в доке, и в обсуждении.

поиск дает:
http://sql.ru/forum/actualsearch.aspx?search=INSERT+SELECT+EXCEPTION+UNIQUE_VIOLATION&sin=0&a=&ma=0&bid=7&dt=-1&s=1&so=1
посмотрите внимательно.
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760814
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ок, понял
вроде так должно быть:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
BEGIN
	INSERT INTO words VALUES (newword);
		EXCEPTION
			WHEN UNIQUE_VIOLATION THEN
				SELECT INTO find_words id FROM words WHERE name=newword;
				RETURN find_words;
SELECT INTO newid currval('public.words_id_seq');	
END;
RETURN newid;

Единственный вопрос есть: можно ли гарантировать что в данном коде SELECT INTO newid currval('public.words_id_seq'); вернёт именно id данной добавленной записи (вроде по доке так и должно быть) а не добавленной в паралельном потоке в это же время ?
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760823
Фотография pamir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
golden13Единственный вопрос есть: можно ли гарантировать что в данном коде SELECT INTO newid currval('public.words_id_seq'); вернёт именно id данной добавленной записи (вроде по доке так и должно быть) а не добавленной в паралельном потоке в это же время ?
Можно.
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760840
Фотография pamir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
golden13ок, понял
вроде так должно быть:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
BEGIN
	INSERT INTO words VALUES (newword);
		EXCEPTION
			WHEN UNIQUE_VIOLATION THEN
				SELECT INTO find_words id FROM words WHERE name=newword;
				RETURN find_words;
SELECT INTO newid currval('public.words_id_seq');	
END;
RETURN newid;

Единственный вопрос есть: можно ли гарантировать что в данном коде SELECT INTO newid currval('public.words_id_seq'); вернёт именно id данной добавленной записи (вроде по доке так и должно быть) а не добавленной в паралельном потоке в это же время ?Хм. В данном написании строка
Код: plaintext
SELECT INTO newid currval('public.words_id_seq');
относится к секции EXCEPTION и будет выполняться только если произойдет ошибка. Но т.к. раньше выполнится return, то она вообще не будет выполняться. Вот вам красивый (на мой вкус) вариант
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
BEGIN
	INSERT INTO words VALUES (newword);
	SELECT INTO newid currval('public.words_id_seq');	
EXCEPTION
	WHEN UNIQUE_VIOLATION THEN
		SELECT INTO newid id FROM words WHERE name=newword;
END;
RETURN newid;
...
Рейтинг: 0 / 0
Транзакции и UNIQUE
    #34760939
golden13
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
о, точно, я тормоз :)
Спасибо большое всем :)
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Транзакции и UNIQUE
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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