Обсуждение: RE: [INTERFACES] locking on database updates

Поиск
Список
Период
Сортировка

RE: [INTERFACES] locking on database updates

От
Gary Stainburn
Дата:
Hi all,

I've just read the last message I sent and apologise for the poor English.
Let me put it a little clearer.

I agree that using a type 'serial' will give me what I want 
regarding the key field for my table, and gets round the problem
of concurrent users trying to create records with the same number.

The problem is that this does not actually give me the number that
was just created.  As there is no guarantee that the other fields in
the table are unique (hence the serial field in the first place) I cannot
simply do a select to retrieve it.

Has anyone any ideas?

Thanks,

Gary
-----Original Message-----
From:    Gary Stainburn [SMTP:gary.stainburn@ringways.co.uk]
Sent:    Tuesday, December 07, 1999 12:21 PM
To:    'dougt@mugc.cc.monash.edu.au'
Cc:    'Pgsql Interfaces'
Subject:    RE: [INTERFACES] locking on database updates


-----Original Message-----
From:    Douglas Thomson [SMTP:dougt@mugc.cc.monash.edu.au]
Sent:    Tuesday, December 07, 1999 11:16 AM
To:    Gary Stainburn
Subject:    Re: [INTERFACES] locking on database updates

!> Is there any way to easily retrieve the sequence number just created =
!> without having the same contension problems I originally wanted to =
!> avoid?
!
!Do you need to find out the next value that will be used before you
!use it? If so there may be a problem...
!
!However, if you only need to do inserts and find out afterwards what
!sequence number got used then there is no problem. Postgres looks
!after making sure multiple simultaneous backend processes don't
!duplicate sequence numbers. I think it actually reserves a few
!numbers in the sequence for each process, so it is possible to get
!small gaps in the sequence, or for the sequence numbers to be not
!strictly chronological...
!
!As for the how - well, I simply selected back the row I had just
!inserted to extract the sequence number column :-)
!
!Doug.

It's not important that I know the number beforehand.  However, as 
this is the only field that is guaranteed to be unique, getting the 
sequence number using  a select statement may not work.
It doesn't matter
-----------------------------------------
Gary Stainburn.
Work: http://www.ringways.co.uk gary.stainburn@ringways.co.uk
REVCOM: http://www.revcom.dhs.org http://www.revcom.org.uk gary.stainburn@revcom.org.uk
-----------------------------------------
The nice thing about standards is that there are so many of them to choose from. -- Andrew S. Tanenbaum
-----------------------------------------



Re: [INTERFACES] locking on database updates

От
"Ross J. Reedstrom"
Дата:
On Tue, Dec 07, 1999 at 04:34:37PM -0000, Gary Stainburn wrote:
> Hi all,
> 
> I've just read the last message I sent and apologise for the poor English.
> Let me put it a little clearer.
> 
> I agree that using a type 'serial' will give me what I want 
> regarding the key field for my table, and gets round the problem
> of concurrent users trying to create records with the same number.
> 
> The problem is that this does not actually give me the number that
> was just created.  As there is no guarantee that the other fields in
> the table are unique (hence the serial field in the first place) I cannot
> simply do a select to retrieve it.
> 
> Has anyone any ideas?

create table foo (bar serial, baz text);
insert into foo (baz) values ('wooble');
select currval('foo_bar_seq');

> 
> Thanks,
> 
> Gary

you're welcome ;-)

Ross
-- 
Ross J. Reedstrom, Ph.D., <reedstrm@rice.edu> 
NSBRI Research Scientist/Programmer
Computer and Information Technology Institute
Rice University, 6100 S. Main St.,  Houston, TX 77005


Re: [INTERFACES] locking on database updates

От
Tom Lane
Дата:
"Ross J. Reedstrom" <reedstrm@wallace.ece.rice.edu> writes:
> create table foo (bar serial, baz text);
> insert into foo (baz) values ('wooble');
> select currval('foo_bar_seq');

I don't think this is safe in a multi-client environment;
what if someone else inserts at about the same time?

Better to doselect nextval('foo_bar_seq');insert into foo values (just-retrieved-value, 'wooble');
which is safer and probably marginally faster (since the
sequence object is touched only once, not twice).
        regards, tom lane


Re: [INTERFACES] locking on database updates

От
"Ross J. Reedstrom"
Дата:
Tom - 
I'm surprised: that one's been beat to death in earlier incarnations
of this FAQ. The currval() function is part of backend state: it
always returns the last value sent to _this connection_. In fact, it's
undefined (and throws an error) in a connection until a nextval() has
been performed. Who ever implemented currval did it right.

============session 1=====================

idas_demo=> create table foo (bar serial, baz text);
NOTICE:  CREATE TABLE will create implicit sequence 'foo_bar_seq' for SERIAL column 'foo.bar'
NOTICE:  CREATE TABLE/UNIQUE will create implicit index 'foo_bar_key' for table 'foo'
CREATE
idas_demo=> insert into foo (baz) values ('wooble');
INSERT 692575 1
idas_demo=> insert into foo (baz) values ('wibble');
INSERT 692576 1
idas_demo=> select currval('foo_bar_seq');
currval
-------     2
(1 row)

============session 2=====================

idas_demo=> select currval('foo_bar_seq');
ERROR:  foo_bar_seq.currval is not yet defined in this session
idas_demo=>  insert into foo (baz) values ('wibble');
INSERT 692608 1
idas_demo=>  insert into foo (baz) values ('wibble');
INSERT 692609 1
idas_demo=> select currval('foo_bar_seq');
currval
-------     4
(1 row)

idas_demo=> 

============session 1=====================

idas_demo=> select currval('foo_bar_seq');
currval
-------     2
(1 row)

idas_demo=> 


I'm not sure it's even slower: since currval is local to the backend,
it may be that it doesn't touch the sequence per se: I'd have to check
the code.

Of the sequence functions, one that's not multi-user safe, as far as
I can tell, is setval(). I think that sets the master sequence counter
for all clients.

Ross

On Tue, Dec 07, 1999 at 12:59:33PM -0500, Tom Lane wrote:
> "Ross J. Reedstrom" <reedstrm@wallace.ece.rice.edu> writes:
> > create table foo (bar serial, baz text);
> > insert into foo (baz) values ('wooble');
> > select currval('foo_bar_seq');
> 
> I don't think this is safe in a multi-client environment;
> what if someone else inserts at about the same time?
> 
> Better to do
>     select nextval('foo_bar_seq');
>     insert into foo values (just-retrieved-value, 'wooble');
> which is safer and probably marginally faster (since the
> sequence object is touched only once, not twice).
> 
>             regards, tom lane


Re: [INTERFACES] locking on database updates

От
Douglas Thomson
Дата:
Gary Stainburn writes:
> I agree that using a type 'serial' will give me what I want
> regarding the key field for my table, and gets round the problem
> of concurrent users trying to create records with the same number.
>
> The problem is that this does not actually give me the number that
> was just created.  As there is no guarantee that the other fields in
> the table are unique (hence the serial field in the first place) I cannot
> simply do a select to retrieve it.
>
> Has anyone any ideas?

For what it is worth, I saved the OID returned by the INSERT (see
PQoidStatus - the details depend on what interface language you use),
and then selected the row I had just inserted using:
    SELECT id FROM name_map WHERE oid=12345

Doug.

Re: [INTERFACES] locking on database updates

От
Tom Lane
Дата:
"Ross J. Reedstrom" <reedstrm@wallace.ece.rice.edu> writes:
> Tom - 
> I'm surprised: that one's been beat to death in earlier incarnations
> of this FAQ. The currval() function is part of backend state: it
> always returns the last value sent to _this connection_.

Yeah, sure, I knew that ... in one brain cell or another, but evidently
not the ones on call today ;-)

A fairly weak rejoinder: if you've got triggers or rules doing things
to your tables behind-your-back, you might still not be able to assume
that the sequence's nextval() will be called only once during any one
SQL query that you issue.  So I still say the nextval-first approach
is sounder than currval-afterwards.  But I must agree it wouldn't
become an issue unless you had some pretty convoluted database
programming going on.
        regards, tom lane


Re: [INTERFACES] locking on database updates

От
marten@feki.toppoint.de
Дата:
> 
> The problem is that this does not actually give me the number that
> was just created.  As there is no guarantee that the other fields in
> the table are unique (hence the serial field in the first place) I cannot
> simply do a select to retrieve it.
When doing development with OO development tools and using wrappers
to handle the oo <-> rdbms wall one has to look at the unique identifier
problem.
Here again, two possible ways are possible:
- let the database handle the serial number stuff- let the software handle the serial number stuff
In general it is said not to use special features of databases if they
are ot portable - the software way is very often very portable.
For our wrapper in Smalltalk/X we decided NOT to use the Postgre support
for serial numbers, but do it on our own.
Several papers are out in the internet, which tells one how to create
such number, which fits several points:
- unique number in multiconnection environment- minimize the amount of communication between client and database  while
handlingthis stuff.
 
The principle for the high-low algorithm is:
- the client gets a session id on startup - asking the database for   the next valid session number.
- the unique keys are created on the client side without any further  interaction between client and database.
- the unique key is based on a session id and a id within a session.
- to get it into one column you may put these values together and perhaps  convert them to a string.
- if the client exits it writes its session value and the actual   id within the session back to the database - for
furtheruse by the  next client.
 
If anyone wishes further information about this you may send me an
e-mail.
Marten