Introdução
Neste laboratório, você vai explorar o gerenciamento de transações no PostgreSQL, um aspecto essencial para garantir a integridade dos dados. Você vai aprender a iniciar e confirmar transações, tratando uma série de operações como uma única unidade de trabalho. Também vai aprender a reverter transações que falharam, definir níveis de isolamento e simular bloqueios com atualizações simultâneas.
Inicie e confirme uma transação
Nesta etapa, você vai aprender a iniciar e confirmar uma transação no PostgreSQL. As transações garantem a integridade dos dados ao tratar uma série de operações como uma única unidade de trabalho. Se qualquer operação da transação falhar, toda a transação será revertida. Assim, você evita atualizações parciais e mantém a consistência dos dados.
Primeiro, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Abra um terminal e execute o comando:
sudo -u postgres psql
O prompt postgres=# deverá aparecer.
Em seguida, crie uma tabela chamada accounts para demonstrar o uso de 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, inicie uma transação com 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 com o comando COMMIT.
COMMIT;
Consulte a tabela accounts para verificar se a transação foi concluída com sucesso.
SELECT * FROM accounts;
O saldo de Alice deverá ter diminuído em $20, e o de Bob deverá ter aumentado em $20.

Por fim, saia do shell psql.
\q
Reverta uma transação que falhou
Nesta etapa, você vai aprender a reverter uma transação que falhou no PostgreSQL. Reverter uma transação é essencial quando ocorre um erro durante uma série de operações no banco de dados. Isso garante que o banco de dados permaneça em um estado consistente.
Você ainda deverá estar conectado ao banco de dados PostgreSQL desde a etapa anterior. Caso não esteja, conecte-se novamente com:
sudo -u postgres psql
Inicie uma nova transação.
BEGIN;
Dentro dessa transação, tente executar uma operação que falhará de propósito: inserir uma chave primária duplicada. Primeiro, consulte o próximo valor disponível para id.
SELECT MAX(id) FROM accounts;
Vamos supor que o resultado seja 2. Agora, tente inserir uma nova conta com id = 1, que já existe.
INSERT INTO accounts (id, name, balance) VALUES (1, 'Eve', 25.00);
Esse comando resultará no erro ERROR: duplicate key value violates unique constraint "accounts_pkey".
Como ocorreu um erro dentro da transação, reverta-a com o comando ROLLBACK para descartar todas as alterações feitas.
ROLLBACK;
Consulte a tabela accounts para verificar se o comando ROLLBACK funcionou.
SELECT * FROM accounts;
A tabela ainda deverá conter apenas as contas de Alice e Bob, com os mesmos saldos registrados ao final da etapa anterior. A operação INSERT que falhou terá sido revertida.

Por fim, saia do shell psql.
\q
Defina e teste níveis de isolamento
Nesta etapa, você vai conhecer os níveis de isolamento de transação no PostgreSQL e aprender a defini-los e testá-los. Os níveis de isolamento controlam o quanto as transações simultâneas ficam isoladas umas das outras. Níveis mais altos oferecem mais proteção contra a corrupção de dados, mas podem reduzir a concorrência.
Você ainda deverá estar conectado ao banco de dados PostgreSQL desde a etapa anterior. Caso não esteja, conecte-se novamente com:
sudo -u postgres psql
Abra duas janelas de terminal separadas. Em cada uma, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Você deverá ver dois prompts postgres=#.
Terminal 1:
sudo -u postgres psql
Terminal 2:
sudo -u postgres psql
No Terminal 1, inicie uma transação e defina o nível de isolamento como READ COMMITTED (o padrão). Execute SET TRANSACTION dentro da transação, antes da primeira consulta.
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
No Terminal 1, consulte o saldo de Alice.
SELECT balance FROM accounts WHERE name = 'Alice';
Anote o saldo. Agora, no Terminal 2, inicie uma transação e atualize o saldo de Alice.
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
UPDATE accounts SET balance = 90.00 WHERE name = 'Alice';
COMMIT;
No Terminal 1, consulte 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 para 90.00 e confirmado pelo Terminal 2.

Agora, teste o nível de isolamento REPEATABLE READ. No Terminal 1, reverta a transação atual, inicie uma nova transação e defina o nível de isolamento como REPEATABLE READ antes de consultar qualquer dado.
ROLLBACK;
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
No Terminal 1, consulte novamente o saldo de Alice.
SELECT balance FROM accounts WHERE name = 'Alice';
Anote 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, consulte novamente o saldo de Alice.
SELECT balance FROM accounts WHERE name = 'Alice';
Como o nível de isolamento é REPEATABLE READ, você ainda verá 90.00, o saldo registrado no snapshot estabelecido pela primeira consulta desta transação, embora o Terminal 2 tenha confirmado o valor 100.00.
Por fim, confirme a transação no Terminal 1.
COMMIT;
Agora, consulte novamente o saldo de Alice no Terminal 1. Como a transação foi concluída, você verá o valor confirmado mais recente (100.00).
SELECT balance FROM accounts WHERE name = 'Alice';
Saia dos dois shells psql.
\q
Simule bloqueios com atualizações simultâneas
Nesta etapa, você vai simular bloqueios com atualizações simultâneas no PostgreSQL. Os bloqueios impedem que transações simultâneas interfiram umas nas outras e ajudam a garantir a integridade dos dados.
Você ainda deverá estar conectado ao banco de dados PostgreSQL desde a etapa anterior. Caso não esteja, conecte-se novamente com:
sudo -u postgres psql
Abra duas janelas de terminal separadas. Em cada uma, conecte-se ao banco de dados PostgreSQL como o usuário postgres. Você deverá ver 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. É essencial usar SELECT ... FOR UPDATE para bloquear a linha.
BEGIN;
SELECT balance FROM accounts WHERE name = 'Alice' FOR UPDATE;
Esse comando consulta o saldo de Alice e bloqueia a 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 o comando no Terminal 2 parecerá ficar travado. Isso acontece porque ele está aguardando a liberação do bloqueio mantido pelo Terminal 1.
Agora, confirme a transação no Terminal 1.
COMMIT;
Depois que você confirmar a transação no Terminal 1, o comando UPDATE no Terminal 2 será executado.
No Terminal 2, confirme a transação.
COMMIT;
Agora, em qualquer um dos terminais, consulte a tabela accounts para verificar as alterações.
SELECT * FROM accounts;
Você deverá ver que o saldo de Alice foi atualizado pela transação no Terminal 2 depois que o Terminal 1 liberou o bloqueio.

Por fim, saia dos dois shells psql.
\q
Este exemplo demonstra como usar SELECT ... FOR UPDATE para simular bloqueios e evitar que atualizações simultâneas interfiram umas nas outras. Sem o bloqueio, as duas transações poderiam ler o mesmo saldo inicial e aplicar suas atualizações com base nesse valor, causando a perda de uma atualização.
Resumo
Neste laboratório, você aprendeu a gerenciar transações no PostgreSQL. Primeiro, conectou-se ao banco de dados PostgreSQL usando psql e criou a tabela de exemplo accounts com dados iniciais.
Em seguida, você praticou o uso de transações: aprendeu a iniciar uma transação com o comando BEGIN, executar várias operações no banco de dados (atualizar os saldos de Alice e Bob) e confirmar a transação com o comando COMMIT para tornar as alterações permanentes. Com isso, você viu o princípio fundamental das transações: tratar uma série de operações como uma única unidade atômica. Você também aprendeu a reverter transações e definir níveis de isolamento. Por fim, simulou bloqueios com atualizações simultâneas para entender como evitar a corrupção de dados.



