AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 104987
Accepted
Petr Přikryl
Petr Přikryl
Asked: 2015-06-25 03:11:05 +0800 CST2015-06-25 03:11:05 +0800 CST 2015-06-25 03:11:05 +0800 CST

Evite violação única em transação atômica

  • 772

É possível criar uma transação atômica no PostgreSQL?

Considere que eu tenho uma categoria de tabela com estas linhas:

id|name
--|---------
1 |'tablets'
2 |'phones'

E o nome da coluna tem restrição exclusiva.

Se eu tentar:

BEGIN;
update "category" set name = 'phones' where id = 1;
update "category" set name = 'tablets' where id = 2;
COMMIT;

Estou entendendo:

ERROR:  duplicate key value violates unique constraint "category_name_key"
DETAIL:  Key (name)=(tablets) already exists.
postgresql transaction
  • 2 2 respostas
  • 9512 Views

2 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2015-06-25T20:34:25+08:002015-06-25T20:34:25+08:00

    Além do que o @Craig forneceu (e corrigindo parte dele):

    As restrições efetivas do Postgres 9.4 , UNIQUEe são verificadas imediatamente após cada linha quando definidas . Isso é diferente de outros tipos de restrições (atualmente apenas (chave estrangeira)) que são verificadas após cada instrução . Nós trabalhamos tudo isso sob esta questão relacionada no SO:PRIMARY KEYEXCLUDENOT DEFERRABLENOT DEFERRABLEREFERENCES

    • Restrição definida DEFERRABLE INITIALLY IMMEDIATE ainda é DEFERRED?

    Não é suficiente que uma restrição UNIQUE(or PRIMARY KEYou ) seja para fazer seu código apresentado com várias instruções funcionar.EXCLUDEDEFERRABLE

    E você não pode usar ALTER TABLE ... ALTER CONSTRAINTpara esta finalidade. Por documentação:

    ALTER CONSTRAINT

    Este formulário altera os atributos de uma restrição que foi criada anteriormente. Atualmente , apenas as restrições de chave estrangeira podem ser alteradas .

    Ênfase em negrito minha. Em vez disso, use:

    ALTER TABLE t
       DROP CONSTRAINT category_name_key
     , ADD  CONSTRAINT category_name_key UNIQUE(name) DEFERRABLE;
    

    Elimine e adicione a restrição de volta em uma única instrução para que não haja janela de tempo para que alguém se infiltre nas linhas ofensivas. Para tabelas grandes, seria tentador conservar o índice exclusivo subjacente de alguma forma, porque é caro excluí-lo e recriá-lo. Infelizmente, isso não parece ser possível com ferramentas padrão (se você tiver uma solução para isso, informe-nos!):

    • Elimine a chave primária sem descartar um índice

    Para uma única declaração tornar a restrição adiável é suficiente:

    UPDATE category c
    SET    name = c_old.name
    FROM   category c_old
    WHERE  c.id     IN (1,2)
    AND    c_old.id IN (1,2)
    AND    c.id <> c_old.id;
    

    Uma consulta com CTEs também é uma única instrução:

    WITH x AS (
        UPDATE category SET name = 'phones' WHERE id = 1
        )
    UPDATE category SET name = 'tablets' WHERE id = 2;
    

    No entanto , para o seu código com várias instruções, você (adicionalmente) precisa realmente adiar a restrição - ou defini-la como INITIALLY DEFERREDqualquer um normalmente é mais caro do que o acima. Mas pode não ser facilmente viável agrupar tudo em uma declaração.

    BEGIN;
    SET CONSTRAINTS category_name_key DEFERRED;
    UPDATE category SET name = 'phones'  WHERE id = 1;
    UPDATE category SET name = 'tablets' WHERE id = 2;
    COMMIT;

    Esteja ciente de uma limitação em conexão com as FOREIGN KEYrestrições, no entanto. Por documentação:

    As colunas referenciadas devem ser as colunas de uma restrição de chave primária ou exclusiva não adiável na tabela referenciada.

    Então você não pode ter os dois ao mesmo tempo.

    • 25
  2. Craig Ringer
    2015-06-25T03:29:40+08:002015-06-25T03:29:40+08:00

    Pelo que entendi, seu problema aqui é que a restrição é verificada após cada instrução, mas você deseja que seja verificada no final da transação, para comparar o estado anterior ao estado posterior, ignorando os estados intermediários.

    Nesse caso, isso é possível com uma restrição adiável .

    Consulte SET CONSTRAINTSe DEFERRABLErestrições conforme documentado em CREATE TABLE.

    Observe que as restrições adiadas têm custos - o sistema precisa manter uma lista delas para verificar no momento do commit, portanto, elas não são boas para transações que fazem grandes conjuntos de alterações. Eles também são mais lentos para verificar.

    Então eu acho que você provavelmente quer:

    ALTER TABLE mytable ALTER CONSTRAINT category_name_key DEFERRABLE;
    

    Observe que parece haver uma limitação na ALTER TABLEdefinição de restrições para DEFERRABLE; você pode ter que DROPrefazer ADDa restrição.

    • 13

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve