Re: Strange/Correct? behavior of SELECT FOR UPDATE

Поиск
Список
Период
Сортировка
От Adrian Klaver
Тема Re: Strange/Correct? behavior of SELECT FOR UPDATE
Дата
Msg-id 56A262CC.9050108@aklaver.com
обсуждение исходный текст
Ответ на Strange/Correct? behavior of SELECT FOR UPDATE  (david.turon@linuxbox.cz)
Список pgsql-general
On 01/22/2016 01:41 AM, david.turon@linuxbox.cz wrote:
> Hi,
>
> we have some question about behavior SELECT FOR UPDATE. We want find
> record with open bounds tstzrange, close it a insert new open. We use
> SELECT FOR UPDATE in function, but sometimes 2rows inserted. I show this
> on simple example with integer data type. Here is:
>
> --tested on postgresql 9.5.0
>
> CREATE TABLE test(x int);
>
> INSERT INTO test VALUES (1);
>
> -------------------------------------------------------------------------
> --transaction1
>
> BEGIN;
>
> SELECT * FROM test WHERE x=1 FOR UPDATE;
>   x
> ---
>   1
> (1 row)
>
> UPDATE test SET x=2 WHERE x=1;
> --UPDATE 1
>
> INSERT INTO test VALUES (1);
> --INSERT 0 1
>
> SELECT * FROM test ;
>   x
> ---
>   2
>   1
> (2 rows)
>
> ------------------------------------------------------------------
> --transaction2
> BEGIN;
>
> SELECT * FROM test WHERE x=1 FOR UPDATE; --here transaction hang, thats
> what we want...
> ---------------------------------------------------------------------
> --transaction1
>
> COMMIT;
> --------------------------------------------------------------------
> --transaction2
> --now lock released
> SELECT * FROM test WHERE x=1 FOR UPDATE;
>   x
> ---
> (0 row)
>
> -- but we cant see inserted row with value 1, only updated records can
> we see

I would take a look at this, in particular the *** sectioned:

http://www.postgresql.org/docs/9.5/interactive/transaction-iso.html

13.2.1. Read Committed Isolation Level

UPDATE, DELETE, SELECT FOR UPDATE, and SELECT FOR SHARE commands behave
the same as SELECT in terms of searching for target rows: they will only
find target rows that were committed as of the command start time.
However, such a target row might have already been updated (or deleted
or locked) by another concurrent transaction by the time it is found. In
this case, the would-be updater will wait for the first updating
transaction to commit or roll back (if it is still in progress). If the
first updater rolls back, then its effects are negated and the second
updater can proceed with updating the originally found row. *** If the
first updater commits, the second updater will ignore the row if the
first updater deleted it, otherwise it will attempt to apply its
operation to the updated version of the row. The search condition of the
command (the WHERE clause) is re-evaluated to see if the updated version
of the row still matches the search condition. If so, the second updater
proceeds with its operation using the updated version of the row. *** In
the case of SELECT FOR UPDATE and SELECT FOR SHARE, this means it is the
updated version of the row that is locked and returned to the client.

As I understand that, it means that the original row that had x=1 no
longer exists as it now has x=2. The subsequent row that was INSERTed
occurred inside transaction 1 and was not visible to transaction 2 when
it started, so when transaction 1 COMMITed the query SELECT * FROM test
WHERE x=1 FOR UPDATE found nothing.



> -- so our function here insert new row with value 1, becouse don't know
> about about existing row
> -- if we tray repeat select now we can see row that was inserted by
> transaction1

I would say you are seeing the row just created above.

> SELECT * FROM test WHERE x=1;
>   x
> ---
>   1
> (1 row)
> -------------------------------------------------------------------------
> We try prevent this situation, i know we can use EXCLUDE index on
> tstzrange column, but transaction2 rollback or we can use LOCK TABLE
> test IN EXCLUSIVE MODE - this working but locks whole table or we need
> ask table again with SELECT FOR UPDATE - some double check before insert
> ...Is there any other way how to close tstzrange with minimum locks?
>
> Its correct behavior or not?
>
> Thanks
>
> David Turoň
>
>
> --
> -------------------------------------
> Ing. David TUROŇ
> LinuxBox.cz, s.r.o.
> 28. rijna 168, 709 01 Ostrava
>
> tel.:    +420 591 166 224
> fax:    +420 596 621 273
> mobil:  +420 732 589 152
> www.linuxbox.cz
>
> mobil servis: +420 737 238 656
> email servis: servis@linuxbox.cz
> -------------------------------------
>


--
Adrian Klaver
adrian.klaver@aklaver.com


В списке pgsql-general по дате отправления:

Предыдущее
От: "David E. Wheeler"
Дата:
Сообщение: Re: Let's Do the CoC Right
Следующее
От: Adrian Klaver
Дата:
Сообщение: Re: Let's Do the CoC Right