Gerenciamento de Transações PostgreSQL

PostgreSQLBeginner
Pratique Agora

Introdução

Neste laboratório, você explorará a gestão de transações PostgreSQL, um aspecto crucial para garantir a integridade dos dados. Você aprenderá como iniciar e confirmar transações, tratando uma série de operações como uma única unidade de trabalho. Também aprenderá a reverter transações falhas, definir níveis de isolamento e simular bloqueios com atualizações concorrentes.

Iniciar e Confirmar uma Transação

Neste passo, você aprenderá como iniciar e confirmar uma transação no PostgreSQL. As transações garantem a integridade dos dados, tratando uma série de operações como uma única unidade de trabalho. Se qualquer operação dentro da transação falhar, a transação inteira é revertida, evitando atualizações parciais e mantendo a consistência.

Primeiro, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Abra um terminal e use o seguinte comando:

sudo -u postgres psql

Agora você deve ver o prompt postgres=#.

Em seguida, crie uma tabela chamada accounts para demonstrar transações.

CREATE TABLE accounts (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    balance DECIMAL(10, 2)
);

Insira alguns dados iniciais na tabela accounts.

INSERT INTO accounts (name, balance) VALUES ('Alice', 100.00);
INSERT INTO accounts (name, balance) VALUES ('Bob', 50.00);

Agora, vamos iniciar uma transação usando o comando BEGIN.

BEGIN;

Dentro da transação, transfira $20 da conta de Alice para a conta de Bob.

UPDATE accounts SET balance = balance - 20.00 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 20.00 WHERE name = 'Bob';

Para tornar essas alterações permanentes, confirme a transação usando o comando COMMIT.

COMMIT;

Verifique se a transação foi bem-sucedida consultando a tabela accounts.

SELECT * FROM accounts;

Você deve ver que o saldo de Alice diminuiu em $20 e o saldo de Bob aumentou em $20.

Saída de exemplo de transação PostgreSQL

Finalmente, saia do shell psql.

\q

Reverter uma Transação Falha

Neste passo, você aprenderá como reverter uma transação falha no PostgreSQL. Reverter uma transação é crucial quando ocorre um erro durante uma série de operações no banco de dados, garantindo que o banco de dados permaneça em um estado consistente.

Você deve estar conectado ao banco de dados PostgreSQL do passo anterior. Caso contrário, conecte-se novamente usando:

sudo -u postgres psql

Vamos iniciar uma nova transação.

BEGIN;

Dentro desta transação, vamos tentar uma operação que falhará intencionalmente. Vamos tentar inserir uma chave primária duplicada. Primeiro, vamos encontrar o próximo valor disponível para id.

SELECT MAX(id) FROM accounts;

Vamos supor que o resultado é 2. Agora, tente inserir uma nova conta com id = 1, que já existe.

INSERT INTO accounts (id, name, balance) VALUES (1, 'Eve', 25.00);

Este comando resultará em um erro ERROR: duplicate key value violates unique constraint "accounts_pkey".

Como ocorreu um erro dentro da transação, reverti a transação para descartar quaisquer alterações feitas. Use o comando ROLLBACK.

ROLLBACK;

Verifique se o ROLLBACK foi bem-sucedido consultando a tabela accounts.

SELECT * FROM accounts;

Você deve ver que a tabela ainda contém apenas as contas de Alice e Bob com seus saldos do final do Passo 1. A operação INSERT falha foi revertida com sucesso.

Exemplo de reversão de transação PostgreSQL

Finalmente, saia do shell psql.

\q

Definir e Testar Níveis de Isolamento

Neste passo, você aprenderá sobre os níveis de isolamento de transações no PostgreSQL e como defini-los e testá-los. Os níveis de isolamento controlam o grau em que transações concorrentes são isoladas umas das outras. Níveis de isolamento mais elevados oferecem maior proteção contra a corrupção de dados, mas podem reduzir a concorrência.

Você deve estar conectado ao banco de dados PostgreSQL do passo anterior. Caso contrário, conecte-se novamente usando:

sudo -u postgres psql

Abra duas janelas de terminal separadas. Em cada terminal, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Você deve ter dois prompts postgres=#.

Terminal 1:

sudo -u postgres psql

Terminal 2:

sudo -u postgres psql

No Terminal 1, defina o nível de isolamento para READ COMMITTED (embora este seja o padrão, vamos defini-lo explicitamente para demonstração).

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

Em seguida, inicie uma transação.

BEGIN;

No Terminal 1, leia o saldo de Alice.

SELECT balance FROM accounts WHERE name = 'Alice';

Note o saldo. Agora, no Terminal 2, inicie uma transação e atualize o saldo de Alice.

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
UPDATE accounts SET balance = 90.00 WHERE name = 'Alice';
COMMIT;

No Terminal 1, leia novamente o saldo de Alice.

SELECT balance FROM accounts WHERE name = 'Alice';

Como o nível de isolamento é READ COMMITTED, você verá o saldo atualizado (90.00) confirmado pelo Terminal 2.

Saldo de Alice atualizado em READ COMMITTED

Agora, vamos testar o nível de isolamento REPEATABLE READ. No Terminal 1, reverti a transação atual e defina o nível de isolamento para REPEATABLE READ.

ROLLBACK;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;

No Terminal 1, leia novamente o saldo de Alice.

SELECT balance FROM accounts WHERE name = 'Alice';

Note o saldo. Agora, no Terminal 2, inicie uma transação e atualize novamente o saldo de Alice.

BEGIN;
UPDATE accounts SET balance = 100.00 WHERE name = 'Alice';
COMMIT;

No Terminal 1, leia novamente o saldo de Alice.

SELECT balance FROM accounts WHERE name = 'Alice';

Como o nível de isolamento é REPEATABLE READ, você ainda verá o saldo original do início da transação, mesmo que o Terminal 2 tenha confirmado um novo valor.

Finalmente, no Terminal 1, confirme a transação.

COMMIT;

Agora, se você ler o saldo de Alice no Terminal 1 novamente, verá o último valor confirmado (100.00).

Captura de tela do nível de isolamento de leitura repetível

Saia dos shells psql em ambos os terminais.

\q

Simular Travas com Atualizações Concorrentes

Neste passo, você simulará travas com atualizações concorrentes no PostgreSQL. As travas são mecanismos usados para impedir que transações concorrentes interfiram umas nas outras, garantindo a integridade dos dados.

Você deve estar conectado ao banco de dados PostgreSQL do passo anterior. Caso contrário, conecte-se novamente usando:

sudo -u postgres psql

Abra duas janelas de terminal separadas. Em cada terminal, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Você deve ter dois prompts postgres=#.

Terminal 1:

sudo -u postgres psql

Terminal 2:

sudo -u postgres psql

No Terminal 1, inicie uma transação e atualize o saldo de Alice. Crucialmente, use SELECT ... FOR UPDATE para travar a linha.

BEGIN;
SELECT balance FROM accounts WHERE name = 'Alice' FOR UPDATE;

Este comando recupera o saldo de Alice e coloca uma trava na linha, impedindo que outras transações a modifiquem até que esta transação seja confirmada ou revertida.

No Terminal 2, inicie uma transação e tente atualizar o saldo de Alice.

BEGIN;
UPDATE accounts SET balance = balance + 10 WHERE name = 'Alice';

Observe que este comando no Terminal 2 parecerá ficar pendente. Isso ocorre porque ele está aguardando que a trava mantida pelo Terminal 1 seja liberada.

Agora, no Terminal 1, confirme a transação.

COMMIT;

Após confirmar a transação no Terminal 1, o comando UPDATE no Terminal 2 prosseguirá.

No Terminal 2, confirme a transação.

COMMIT;

Agora, em qualquer terminal, consulte a tabela accounts para verificar as alterações.

SELECT * FROM accounts;

Você deve ver que o saldo de Alice foi atualizado pela transação no Terminal 2 após o Terminal 1 liberar a trava.

Simulação de atualização concorrente PostgreSQL

Finalmente, saia dos shells psql em ambos os terminais.

\q

Este exemplo demonstra como SELECT ... FOR UPDATE pode ser usado para simular travas e impedir que atualizações concorrentes interfiram umas nas outras. Sem a trava, ambas as transações poderiam ler o mesmo saldo inicial e aplicar suas atualizações com base nesse valor, levando a uma atualização perdida.

Resumo

Neste laboratório, você aprendeu como gerenciar transações no PostgreSQL. Começou conectando-se ao banco de dados PostgreSQL usando psql e criando uma tabela de amostra accounts com dados iniciais.

Em seguida, concentrou-se na demonstração do uso de transações. Você aprendeu como iniciar uma transação usando o comando BEGIN, realizar várias operações no banco de dados (atualizando os saldos de Alice e Bob) e, em seguida, confirmar a transação usando o comando COMMIT para tornar as alterações permanentes. Isso ilustrou o princípio fundamental das transações: tratar uma série de operações como uma única unidade atômica. Você também aprendeu como reverter transações e definir níveis de isolamento. Finalmente, simulou travas com atualizações concorrentes para entender como evitar a corrupção de dados.