PostgreSQL Prático/Transações

8 – TransaçõesEditar

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.