Обсуждение: Re: [pgsql-ru-general] атомарно сохранить или проапдейтить
1) можно поменять местами -- пробуем вставлять, если ошибка, то делаем update
2) немного более правильно делать это "ближе к серверу", для этого можно написать plpgsql-функцию, см Example 39-2. Exceptions with UPDATE/INSERT http://www.postgresql.org/docs/9.1/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING
3) ещё правильнее (и моднее) -- это использовать CTE http://vibhorkumar.wordpress.com/2011/10/26/upsertmerge-using-writable-cte-in-postgresql-9-1/
3) ещё правильнее (и моднее) -- это использовать CTE http://vibhorkumar.wordpress.com/2011/10/26/upsertmerge-using-writable-cte-in-postgresql-9-1/
2012/6/20 Dmitry E. Oboukhov <unera@debian.org>
приходят внешние данные с уникальным ID (uuid)
нужно эту запись либо создать, либо проапдейтить новыми значениями
делал так:
dbh->begin_work; # начали транзакцию
my $record = dbh->single( # попытка апдейта
q{
UPDATE
table
SET
some=?
WHERE
eid=?
RETURNING *
}, $val, $eid
);
unless ($record) { # инсерт после неудачи апдейта
my $record = dbh->single(
q{
INSERT INTO
table
(eid, some)
VALUES
(?, ?)
RETURNING *
}, $eid, $val
);
}
dbh->commit; # коммит транзакции
то есть в транзакции пытаемся сперва сделать апдейт имеющегося, а если
его нет в БД то затем делаем insert.
так вот при таком подходе при приходе одновременных запросов иногда
падает на втором insert'е с жалобой что такой ключ уже существует.
как правильно решить данную проблему?
--
. ''`. Dmitry E. Oboukhov
: :’ : email: unera@debian.org jabber://UNera@uvw.ru
`. `~’ GPGKey: 1024D / F8E26537 2006-11-21
`- 1B23 D4F8 8EC0 D902 0555 E438 AB8C 00CF F8E2 6537
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iEYEAREDAAYFAk/iF0cACgkQq4wAz/jiZTcyfACg0YDwJvZbxKBenjotM7WDdWL/
YJoAoNgQ6tz13jtNGlkIYdf4XGoATD/Y
=OQgr
-----END PGP SIGNATURE-----
кстати, у нашего польского собрата по футбольному несчастью depesz-а совсем свежий пост на эту тему, советую
http://www.depesz.com/2012/06/10/why-is-upsert-so-complicated/
2012/6/21 Nikolay Samokhvalov <samokhvalov@gmail.com>
1) можно поменять местами -- пробуем вставлять, если ошибка, то делаем update2) немного более правильно делать это "ближе к серверу", для этого можно написать plpgsql-функцию, см Example 39-2. Exceptions with UPDATE/INSERT http://www.postgresql.org/docs/9.1/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING
3) ещё правильнее (и моднее) -- это использовать CTE http://vibhorkumar.wordpress.com/2011/10/26/upsertmerge-using-writable-cte-in-postgresql-9-1/2012/6/20 Dmitry E. Oboukhov <unera@debian.org>-----BEGIN PGP SIGNATURE-----
приходят внешние данные с уникальным ID (uuid)
нужно эту запись либо создать, либо проапдейтить новыми значениями
делал так:
dbh->begin_work; # начали транзакцию
my $record = dbh->single( # попытка апдейта
q{
UPDATE
table
SET
some=?
WHERE
eid=?
RETURNING *
}, $val, $eid
);
unless ($record) { # инсерт после неудачи апдейта
my $record = dbh->single(
q{
INSERT INTO
table
(eid, some)
VALUES
(?, ?)
RETURNING *
}, $eid, $val
);
}
dbh->commit; # коммит транзакции
то есть в транзакции пытаемся сперва сделать апдейт имеющегося, а если
его нет в БД то затем делаем insert.
так вот при таком подходе при приходе одновременных запросов иногда
падает на втором insert'е с жалобой что такой ключ уже существует.
как правильно решить данную проблему?
--
. ''`. Dmitry E. Oboukhov
: :’ : email: unera@debian.org jabber://UNera@uvw.ru
`. `~’ GPGKey: 1024D / F8E26537 2006-11-21
`- 1B23 D4F8 8EC0 D902 0555 E438 AB8C 00CF F8E2 6537
Version: GnuPG v1.4.10 (GNU/Linux)
iEYEAREDAAYFAk/iF0cACgkQq4wAz/jiZTcyfACg0YDwJvZbxKBenjotM7WDdWL/
YJoAoNgQ6tz13jtNGlkIYdf4XGoATD/Y
=OQgr
-----END PGP SIGNATURE-----