> Bem, não fiz algo muito bem feito, mas pode ilustrar bem o > funcionamento do SELECT FOR UPDATE: > > CREATE TABLE CONTADOR( > ID INTEGER NOT NULL, > DESCRICAO VARCHAR(30) NOT NULL, > VALOR INTEGER NOT NULL > ); > > ALTER TABLE CONTADOR ADD PRIMARY KEY( id ); > > -- Função que retorna o último contador gravado e incrementa 1 ao final > CREATE OR REPLACE FUNCTION UF_ADD_CONTADOR( ai_id INTEGER ) > RETURNS INTEGER AS > $BODY$ > DECLARE > li_id INTEGER; > BEGIN > -- Pega o valor. A cláusula FOR UPDATE faz um ROW LOCK EXCLUSIVE > -- apenas sobre o registro especificado. Somente após um COMMIT ou > -- ROLLBACK o LOCK será liberado. > -- NOTA: o registro deve existir na tabela. Você pode fazer o > tratamento > -- para criá-lo caso não exista ou então deixar pré-cadastrado > SELECT > valor > INTO > li_id > FROM > contador > WHERE > id = ai_id > FOR UPDATE; > > -- Incrementa o valor do contador > UPDATE > contador > SET > valor = valor +1 > WHERE > id = ai_id; > > -- Retorna o valor > RETURN li_id; > END > $BODY$ > LANGUAGE 'plpgsql' VOLATILE; > > > -- Insere o registro na tabela de contador para que possa ser incrementado > INSERT INTO contador ( id, descricao, valor ) VALUES( 1, 'Contador Teste', 1 > ); > > -- Para recuperar o valor dentro de uma transação... > -- NOTA: se outra transação estiver executando o mesmo comando, ela irá > aguardar > -- até que a primeira transação realize um ROLLBACK ou COMMIT. > -- Caso um ROLLBACK seja executado, o valor não é incrementado. > SELECT uf_add_contador( 1 ) as valor
Sinto muito, mas essa implementação pode ter um efeito colateral. Duas transações concorrentes podem "catar" o mesmo valor. O SELECT... FOR UPDATE não impede a leitura do registro. Pode ocorrer um ROLLBACK automático na transação que chegar por último na hora fizer o UPDATE da sua função. Se a aplicação não tratar esse ROLLBACK (e tentar novamente até conseguir sucesso no COMMIT) isso pode se tornar uma bola de neve e um catastrófico "lock geral" numa aplicação com muita concorrência. A implementação de sequências foi inventada exatamente pra isso, sem dor de cabeça. Não acho legal tentar contornar por fora algo que um banco de dados sério sabe fazer com maestria. []s Flavio Gurgel _______________________________________________ pgbr-geral mailing list pgbr-geral@listas.postgresql.org.br https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral