Atenção: por essa edição ser muito antiga não há arquivo PDF para download.
Os artigos dessa edição estão disponíveis somente através do formato HTML.

capnet43.jpg

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-usuário com contexto transacional. A consistência nesse contexto é mantida através de um modelo multi versão, onde cada transação trabalha com uma imagem dos dados no estado que eles se encontravam no início da transação.

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ê-los (write) e vice-versa.

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 - 100.00 where codigo = 27 ;

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-repeatable reads: os dados lidos numa transação podem sofrer alterações em outras transações. Numa segunda leitura, no mesmo contexto transacional, os dados recuperados podem ser diferentes da primeira leitura;

·         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-se alterar a opção default_transaction_isolation no arquivo postgresql.conf. Para configurar a nível de sessão, deve-se utilizar a instrução SET TRANSACTION ISOLATION LEVEL { read commited | serializable }.

 

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 - 100.00 where codigo = 27 ;

6

1

update contas set saldo = saldo + 100.00 where codigo = 38 ;

7

1

select * from contas where saldo > 1000.00 ;

codigo        descricao      descricao

19             Conta C                 1054.00

38             Conta B                  1073.00

8

2

select * from contas where saldo > 1000.00 ;

codigo        descricao      descricao

19             Conta C                  1054.00

9

1

COMMIT;

10

2

select * from contas where saldo > 1000.00 ;

codigo         descricao      descricao

19                Conta C                     1054.00

38                Conta B                     1073.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 - 100.00 where codigo = 27 ;

7

1

update contas set saldo = saldo + 100.00 where codigo = 38 ;

8

1

select * from contas where saldo > 1000.00 ;

codigo        descricao      descricao

19             Conta C                 1054.00

38             Conta B                  1073.00

9

2

select * from contas where saldo > 1000.00 ;

codigo        descricao      descricao

19             Conta C                  1054.00

10

1

COMMIT;

11

2

select * from contas where saldo > 1000.00 ;

codigo         descricao      descricao

19                Conta C                     1054.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á!