artigo SQL Magazine 7 - PostgreeSQL Transações - Parte I
Artigo da Revista SQL Magazine -Edição 7.
Os artigos dessa edição estão disponíveis somente através do formato HTML.
Clique aqui para ler todos os artigos desta edição
PostgreSQL
Transações – Parte I
Podemos dizer, de forma simplificada, que transação é um mecanismo que permite a execução de várias tarefas de forma única, como se estivessem contidas em um bloco, possibilitando o cancelamento total ou parcial das operações executadas nesse contexto, além de controlar o nível de acesso e visibilidade das atualizações efetuadas entre sessões simultâneas.
Para efetuar e controlar essas tarefas, diversos sistemas de banco de dados utilizam bloqueios de tabelas e/ou registros (locks) para controle de concorrência e para garantir o contexto transacional. O PostgreSQL utiliza, a partir da versão 6.5, o modelo MVCC (Multiversion Concurrency Control).
O modelo MVCC é uma técnica utilizada para melhorar a performance do banco de dados em um ambiente multi
Uma vez iniciada uma transação no modelo MVCC, não é levado em consideração as alterações das outras transações simultâneas, proporcionando isolamento completo para cada sessão do banco de dados.
A principal diferença do MVCC para o modelo tradicional é que os bloqueios obtidos pelo MVCC ao consultar os dados (read) não conflitam com os bloqueios obtidos ao escrevê
Por exemplo, uma sessão pode executar um update na tabela e ao mesmo tempo outra sessão pode ler o registro que está sendo alterado; a leitura retornará os dados como estavam antes da alteração, pois o PostgreSQL faz um tipo de “cópia adicional” do registro.
O PostgreSQL também disponibiliza instruções de bloqueio explícito, a nível de tabela e/ou registro, por questões de compatibilidade com o SQL ANSI, para aplicativos que utilizam locks em suas regras de negócio e não se adaptariam ao modelo MVCC, e para manter compatibilidade com versões do PostgreSQL anteriores a 6.5.
O uso correto do MVCC geralmente proporciona melhor performance do que o modelo tradicional; O modelo de bloqueios, em alguns casos, exige que a transação seja finalizada para que o acesso aos registros por ela manipulados sejam liberados para outras sessões, ao passo que no modelo MVCC esse acesso é direto, independente do término das transações.
A Listagem 1 mostra a execução de vários comandos dentro de uma transação.
begin ;
insert into movimentos ( conta, tipo, valor ) values ( 27, 'D', 100.00) ;
insert into movimentos ( conta, tipo, valor ) values ( 38, 'C', 100.00) ;
update contas set saldo = saldo
update contas set saldo = saldo + 100.00 where codigo = 38 ;
commit ;
Listagem 1
Isolamento de transações
Isolamento de transações é o recurso que permite que transações concorrentes não interfiram umas com as outras. O SQL ANSI define 4 tipos de isolamento: read uncommited, read commited, repeatable read e serializable; porém, o PostgreSQL trabalha apenas com dois desses quatro tipos: read commited e serializable. Esses níveis de isolamento são definidos com base nas seguintes situações não desejáveis:
·dirty reads: ocorre quando os dados não “comitados” de uma transação são lidos por outra transação;
·non
·phantom read: uma transação recupera um conjunto de registros a partir de uma determinada condição. Outra transação insere um ou mais registros que atendam a condição citada. Caso a primeira transação recupere novamente o mesmo conjunto de linhas, as linhas inseridas na transação concorrente são exibidas.
Quando uma transação é executada no nível de isolamento Read Commited, as transações concorrentes só enxergam os dados por ela atualizados após a execução da instrução COMMIT.
A transação com nível de isolamento Serializable não é afetada pelas modificações/inserções de transações concorrentes, mesmo após serem efetivadas.
create table contas
(
codigo integer primary key,
descricao varchar(100),
saldo numeric(15, 2)
) ;
create table movimentos
(
id serial primary key,
conta integer not null,
tipo char(1),
valor numeric(15,2)
) ;
insert into contas ( codigo, descricao, saldo ) values ( 27, 'Conta A', 854.00 ) ;
insert into contas ( codigo, descricao, saldo ) values ( 38, 'Conta B', 973.00 ) ;
insert into contas ( codigo, descricao, saldo ) values ( 19, 'Conta C', 1054.00 ) ;
Listagem 2
Para exemplificar, considere o script da listagem 2. As tabelas 1 e 2 mostram dois exemplos de níveis de isolamento. A coluna Ordem indica a ordem de execução dos comandos e Sessão indica em qual sessão o comando foi executado.
NOTA: Duas seções simultâneas podem ser geradas a partir de duas instâncias do aplicativo psql.
A tabela 1 mostra o isolamento read commited. As alterações realizadas na sessão 1 somente são visíveis para as outras seções após a execução do COMMIT. Por sua vez, no nível de isolamento serializable, exemplificado na tabela 2, mesmo após a execução do COMMIT as alterações efetuadas por uma sessão não são visualizadas pela outra.
A diferença entre os dois níveis é visível no resultado do SELECT após a execução do COMMIT. Enquanto no modo read commited o comando SELECT retorna dois registros, no modo serializable o comando retorna somente um registro, pois as alterações de outras seções não afetam a sessão corrente.
Nota
O nível de isolamento da transação pode ser definido a nível global ou somente na sessão corrente. Para configurar o nível de isolamento a nível global, deve
Ordem |
Sessão |
Comando/Resultado |
1 |
1 |
begin; |
2 |
2 |
begin; |
3 |
1 |
insert into movimentos ( conta, tipo, valor ) values ( 27, 'D', 100.00) ; |
4 |
1 |
insert into movimentos ( conta, tipo, valor ) values ( 38, 'C', 100.00) ; |
5 |
1 |
update contas set saldo = saldo |
6 |
1 |
update contas set saldo = saldo + 100.00 where codigo = 38 ; |
7 |
1 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 38Conta B1073.00 |
8 |
2 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 |
9 |
1 |
COMMIT; |
10 |
2 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 38Conta B1073.00 |
11 |
2 |
COMMIT; |
Tabela 1 – Execução de comandos com nível de isolamento Read Commited
Ordem |
Sessão |
Comando/Resultado |
1 |
1 |
begin; |
2 |
2 |
begin; |
3 |
2 |
set transaction isolation level serializable; |
4 |
1 |
insert into movimentos ( conta, tipo, valor ) values ( 27, 'D', 100.00) ; |
5 |
1 |
insert into movimentos ( conta, tipo, valor ) values ( 38, 'C', 100.00) ; |
6 |
1 |
update contas set saldo = saldo |
7 |
1 |
update contas set saldo = saldo + 100.00 where codigo = 38 ; |
8 |
1 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 38Conta B1073.00 |
9 |
2 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 |
10 |
1 |
COMMIT; |
11 |
2 |
select * from contas where saldo > 1000.00 ; codigodescricaodescricao 19Conta C1054.00 |
12 |
2 |
COMMIT; |
Tabela 2 – Execução de comandos com nível de isolamento Serializable
Conclusões
O PostgreSQL tem total suporte a contextos transacionais que seguem o padrão ACID (atomicidade, consistência, isolamento e durabilidade), através do modelo de concorrência de múltiplas versões. Na próxima edição veremos um pouco sobre bloqueios. Até lá!
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo