PostgreSQL Prático/Transações
8 – Transações
[editar | editar código-fonte]Transação - é a realização de um conjunto de comandos de uma só vez. Uma transação acontece por completo (todas as operações) ou nada acontece. Também a transação deve garantir um nível de isolamento das demais transações, de maneira que as demais transações somente enxerguem as operações após a transação concluída.
Caso haja um erro qualquer na transação ou falha no sistema o SGBR irá executar um comando ROLLBACK. Transações são uma forma de dar suporte às operações concorrentes, garantindo a segurança e integridade das informações. Garantir que duas solicitações diferentes não efetuarão uma mesma operação ao mesmo tempo.
Ao consultar o banco de dados, uma transação enxerga um snapshot (instantâneo) dos dados, como estes eram no exato momento em que a consulta foi solicitada, desprezando as mudanças ocorridas depois disso.
O PostgreSQL trata a execução de qualquer comando SQL como sendo executado dentro de uma transação.
Na versão 8 apareceram os SAVEPOINTS (pontos de salvamento) , que guardam as informações até eles. Isso salva as operações existentes antes do SAVEPOINT e basta um ROLLBACK TO para continuar com as demais operações.
O PostgreSQL mantém a consistência dos dados utilizando o modelo multiversão MVCC (Multiversion Concurrency Control), que permite que leitura não bloqueie escrita nem escrita bloqueie leitura.
O PostgreSQL também conta com um nível de isolamento chamado serializable (serializável), que é mais rigoroso e emula execução serial das transações.
BEGIN;
UPDATE contas SET saldo = saldo – 100.00 WHERE codigo = 5;
SAVEPOINT meu_ponto_de_salvamento;
UPDATE contas SET saldo = saldo + 100.00 WHERE codigo = 5;
-- ops ... o certo é na conta 6
ROLLBACK TO meu_ponto_de_salvamento;
UPDATE contas SET saldo = saldo + 100.00 WHERE conta = 6;
COMMIT;
Exemplos:
CREATE TABLE contas(codigo INT2 PRIMARY KEY, nome VARCHAR(40), saldo NUMERIC());
INSERT INTO contas values (5, 'Ribamar', 500.45);
Uma transação é dita um processo atômico, o que significa que ou acontecem todas as suas operações ou então nenhuma será salva.
Vamos iniciar a seguinte transação na tabela acima:
BEGIN; -- Iniciar uma transação
UPDATE contas SET saldo = 800.35 WHERE codigo= 5;
SELECT nome,saldo FROM contas WHERE codigo = 5;
COMMIT; -- Executar todos os comandos da transação
'''Agora para testar se de fato todas as operações foram salvas execute:'''
SELECT nome,saldo FROM contas WHERE codigo = 5;
Vamos a outro teste da atomicidade das transações. Intencionalmente vamos cometer um erro no SELECT (FRON) (Com N, quando deveria ser com M):
BEGIN; -- Iniciar uma transação
UPDATE contas SET saldo = 50.85 WHERE codigo= 5;
SELECT nome,saldo FROM contas WHERE codigo = 5;
COMMIT; -- Executar todos os comandos da transação
Isso causará um erro e o comando ROLLBACK será automaticamente executado, o que garante que nenhuma das operações será realizada. Então execute a consulta para testar se houve a atualização:
SELECT nome,saldo FROM contas WHERE codigo = 5;
Remover Campo (versões anteriores a 7.3 não contam com esse recurso):
BEGIN;
LOCK TABLE nometabela;
INTO TABLE nomenovo FROM nometabela;
DROP TABLE nometabela;
ALTER TABLE nomenovo RENAME TO nometabela;
COMMIT;
Alterar Tipos de Dados (versões antigas):
BEGIN;
ALTER TABLE tabela ADD COLUMN novocampo novotipodados;
UPDATE tabela SET novocampo = CAST (antigocampo novotipodados);
ALTER TABLE tabela DROP COLUMN antigocampo;
COMMIT;
Transações que não se Concretizam
BEGIN; -- Iniciar uma transação
UPDATE contas SET saldo = 50.85 WHERE codigo= 5;
SELECT nome,saldo FRON contas WHERE codigo = 5;
ROLLBACK; -- Cancelando todos os comandos da transação
SELECT nome,saldo FRON contas WHERE codigo = 5;
BEGIN; -- Iniciar uma transação
CREATE TABLE teste (id integer, nome text);
INSERT INTO teste VALUES (1, 'Teste1');
INSERT INTO teste VALUES (2, 'Teste2');
DELETE FROM teste;
COMMIT; -- gravar resultados
SELECT * FROM TESTE;
--
BEGIN;
CREATE TABLE teste (id integer, nome text);
INSERT INTO teste VALUES (3, 'Teste3');
INSERT INTO teste VALUES (4, 'Teste4');
DELETE FROM teste;
ROLLBACK;
SELECT * FROM TESTE;
Detalhes sobre conflitos de bloqueios:
http://www.postgresql.org/docs/current/static/explicit-locking.html
Isolamento de Transações
O nível de isolamento padrão do PostgreSQL é o Read Committed (leitura efetivada). Uma consulta SELECT realizada com este nível perceberá os registros existente no início da consulta. Este é o nível mais flexível.
Existe também o nível serializable, mais rigoroso. Os níveis Read uncommitted e Repeatable read são suportados, mas assumem a forma de um dos dois anteriores.
Setando o Nível de Isolamento de uma transação:
banco=# \h set transaction
Comando: SET TRANSACTION Descrição: define as características da transação atual Sintaxe:
SET TRANSACTION modo_transação [, ...]
SET SESSION CHARACTERISTICS AS TRANSACTION modo_transação [, ...]
onde modo_transação é um dos:
ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
READ WRITE | READ ONLY
Exemplo:
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Aqui as consultas da transação;
...
COMMIT;
Controle de Simultaneidade no Capítulo 12 do manual oficial.