BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
- Aula 13 TRANSAÇÕES EM BANCO DE DADOS
1. TRANSAÇÃO
O termo transação refere-se a uma coleção de operações que formam uma única unidade
de trabalho lógica. Por exemplo, a transferência de dinheiro de uma conta para outra é uma
transação consistindo de duas atualizações, uma para cada conta.
Uma transação é uma unidade de execução do programa que acessa e possivelmente
atualiza vários itens de dados. Para garantir a integridade dos dados, é necessário que o SGBD
mantenha as seguintes propriedades das transações: atomicidade, consistência, isolamento e
durabilidade.
- Atomicidade: uma transação é uma unidade atômica de processamento; ou ela será
executada em sua totalidade ou não será de modo nenhum.
- Consistência: uma transação deve ser preservadora de consistência se sua execução
completa fizer o banco de dados passar de um estado consistente para outro também consistente.
- Isolamento: uma transação deve ser executada como se estivesse isolada das demais.
Isto é, a execução de uma transação não deve sofrer interferência de quaisquer outras transações
concorrentes.
- Durabilidade: as mudanças aplicadas ao banco de dados por uma transação efetivada
devem persistir no banco de dados. Essas mudanças não devem ser perdidas em razão de uma
falha.
Essas propriedades normalmente são conhecidas como propriedades ACID. Esse acrônimo
é derivado da primeira letra de cada uma das quatro propriedades.
Quando se trabalham com transações, é necessário que se faça pelo menos duas ressalvas.
A primeira é que em certas situações é interessante se agregar vários comandos como sendo
integrantes de uma mesma transação, como, por exemplo, em uma transferência bancária que
envolve a retirada de dinheiro de uma conta e o acréscimo em outra como se fosse apenas uma
única operação lógica. A segunda ressalva é que em outras situações se faz necessário sacrificar
ou flexibilizar as características ACID em virtude da necessidade de maior desempenho.
1.1. Estados de uma Transação
Na ausência de falhas, todas as transações são completadas com sucesso. Porém, uma
transação nem sempre pode completar sua execução com sucesso. Caso isso ocorra, essa
transação é considerada abortada.
Se tivermos que garantir a propriedade de atomicidade, uma transação abortada não pode
ter efeito sobre o estado do banco de dados. Assim, qualquer mudança que a transação abortada
tenha feito no banco de dados deve ser desfeita. Quando as mudanças causadas por uma
transação abortada tiverem sido desfeitas, dizemos que a transação foi revertida (rolled back). Se
1
BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
uma transação foi executada com sucesso, diz-se que foi confirmada (committed). Assim, é
possível estabelecer vários estados para as transações:
- Active: corresponde ao estado inicial. A transação fica neste estado enquanto está sendo
executada.
- Partially Committed: Após a última instrução ter sido executada.
- Failed: Depois de se descobrir que a execução normal não pode continuar.
- Aborted: quando a transação foi revertida e a base de dados voltou ao estado anterior a
transação
- Committed: como dito antes, após uma conclusão da transação com êxito.
Figura 1 - Estados das transações
1.2. Controle de concorrência
Após uma abordagem inicial sobre transações, é fácil verificar que estas fazem sentido num
âmbito concorrente. O controle de concorrência é uma das coisas mais importantes em bases de
dados grandes. Tomemos novamente como exemplo o caso de um banco, em que várias pessoas
podem acessar aos mesmos dados simultaneamente, fazendo várias operações iguais ou
diferentes. Caso não haja um controlo de concorrência forte, poderiam existir problemas sérios.
Para lidar com este problema, foram desenvolvidas técnicas específicas para lidar com esta
concorrência.
2
BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
- Protocolos Baseados em Locks: Estes protocolos baseiam-se, tal como o nome indica,
na utilização de locks. Através destas propriedades, podemos garantir que o acesso a
determinados dados são feitos de acordo com estes locks, mas basicamente a idéia é que se uma
transação está acessando determinados dados, mais nenhuma outra transação pode acessar estes
(modo exclusivo). Através de propriedades de locks e unlocks conseguimos estabelecer estas
regras. Note que estes locks podem ser do tipo exclusivo, em que se uma transação obtém um
exclusive-mode lock mais nenhuma transação poderá ler ou escrever sobre esses dados, ou
também podem ser do tipo shared, em que se uma transação obtém o shared-mode lock qualquer
outra transação poderá ler os mesmos dados, mas nunca escrever neles. Um protocolo deste
gênero muito conhecido é o Two-Phase Locking Protocol, que consiste em duas fases distintas,
Growing phase, onde são obtidos os locks sem nunca os libertar, e a shrinking phase, onde uma
transação liberta os locks, não os podendo obter mais.
- Protocolos Baseados em Time-Stamps: Para cada transação no sistema, é atribuído
um time-stamp, antes de esta começar a execução. Há então duas formas de funcionamento: a
atribuição do time-stamp pode ser com a utilização do clock do sistema ou utilizando um contador
lógico, que é incrementado sempre que uma nova transação entra no sistema. Através destes
time-stamps conseguem-se fazer um controle de concorrência.
- Protocolos Multi-Versões: De forma a maximizar ainda mais a concorrência, este tipo
de protocolo cria várias cópias do mesmo item. Assim, cada write (Q) cria uma nova versão de Q e
quando Q é chamado para leitura, o sistema elege a versão do Q mais apropriada, garantida a
serialização. É neste âmbito que surgem então os protocolos Multiversion Timestamp Ordering e o
conhecido Two-Phase Locking.
Existem muitos outros protocolos, no entanto esses se destacam como mais utilizados.
1.3. Gestão de Concorrência no PostgreSQL
O PostGreSQL implementa uma política de auto-commit. Desta forma, cada instrução é
tratada como uma transação. Um read é uma transação, um write é outra, etc… Há então duas
formas de contornar esta situação: uma é simplesmente desligar o auto-commit, através da
instrução \SET AUTOCOMMIT OFF. Assim, é tudo considerado uma transação até que a instrução
commit seja executada. A outra solução passa por indicar explicitamente o início e o fim de uma
transação usando o comando BEGIN no início da transação e o comando COMMIT; no final desta.
Caso se pretenda anular a transação, ao invés do comando COMMIT é possível introduzir o
comando ROLLBACK.
1.3.1. GARANTIA DE ISOLAMENTO
O PostgreSQL, ao invés de muitos outros SGBD’s, mantém os dados coerentes através da
utilização de modelos multi-versão (Multiversion Concurrency Control, MVCC). Assim, cada
transação vê uma versão da base de dados (snapshot) tal como era em algum tempo atrás,
independentemente do estado atual dos dados, evitando assim o problema de uma transação
3
BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
poder ver os dados incoerentes. Protocolos em nível de locks de tabela e tupla também são
possíveis no PostgreSQL para aplicações que não se adaptem bem ao funcionamento do modelo
MVCC, sendo que é necessário estabelecer manualmente o nível de granularidade desejado.
Contudo, um uso cuidado no MVCC é melhor que a utilização de locks.
1.3.2. ISOLAMENTO NAS TRANSAÇÕES
O SQL standard define quatro níveis de isolamento de transações de acordo com três
fenômenos que não devem acontecer entre transações concorrentes, sendo os fenômenos os
seguintes: dirty reading, nonrepeatable read e phantom read.
- Dirty reading: uma transação lê dados que foram modificados por uma outra transação
concorrente que ainda não realizou o comando commit;
- Nonrepeatable read: uma transação re-lê dados e descobre que os estes foram
modificados por uma outra transação;
- Phantom read: uma transação executa novamente uma pergunta e descobre que os
valores que satisfazem a pergunta são diferentes da anterior, devido a um commit de uma outra
transação.
Os quatro níveis de isolamento das transações SQL são as seguintes:
Tabela 1- Nível de isolamento das transações SQL
Isolation level
Read uncommitted
Read committed
Repeatable read
Serializable
Nonrepeatable
Read
Possible
Possible
Not Possible
Not Possible
Dirty Read
Possible
Not Possible
Not Possible
Not Possible
Phantom Read
Possible
Possible
Possible
Not Possible
O PostgreSQL suporta o Read Commited e o Serializable. Como o padrão SQL tem mais
dois elementos, o Read Uncommitted é tratado como um Repetable Read que é tratado como
Serializable. O Read Commited é o grau de isolamento padrão do sistema em questão.
1.3.3. NÍVEIS DE GRANULARIDADE (Locks)
O PostgreSQL permite a utilização de locks com vários níveis de granularidade (explicit
locking), em nível de tabela, em nível de tuplas e, em versões mais recentes, os chamados
advisory locks. Para criar locks em nível de tabela, a instrução utilizada é a seguinte:
LOCK [ TABLE ] [ ONLY ] name [, ...] [ IN lockmode MODE ] [ NOWAIT ]
Sendo que lock mode é um dos seguintes:
ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE | SHARE
| SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
4
BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
1.3.4. CONSISTÊNCIA DE DADOS NO POSTGRESQL
Como no sistema PostgreSQL um leitor nunca realiza locks sobre os dados, dados lido
numa transação podem ser escritos por cima por uma outra corrente transação, ou seja, os dados
lidos podem não ser sempre os mais atuais. Para resolver este problema surge um pouco à
necessidade de se utilizarem os locks, SELECT FOR UPDATE, SELECT FOR SHARE, ou fazendo
locks sobre toda a tabela, como forma de impossibilitar a modificação dos dados em questão.
Porém, a utilização excessiva de locks pode limitar, e muito, a concorrência de uma base
de dados, que, é bastante proveitosa em inúmeras situações.
1.3.5. ATOMICIDADE E DURABILIDADE NO POSTGRESQL
De acordo com as propriedades anteriores, é justo dizer que as transações funcionam
como um todo. Ou a transação é executada na sua totalidade, ou nada dela é executada. Caso
haja falha, a base de dados é restaurada, através de mecanismos de rollback, que serão
abordados no seguinte tópico. O mesmo acontece com a durabilidade. Caso a transação se
concretize os dados são guardados em memória estável e o utilizador é notificado do sucesso da
operação. Em caso de falha, os dados não são guardados e o utilizador é notificado da falha que
ocorreu.
1.3.6. MECANISMOS DE ROLLBACK E RECUPERAÇÃO NO POSTGRESQL
Por vezes, em transações complexas e grandes, há necessidade de estabelecer save points.
Estas são pontos de restauração do sistema, considerado um ponto especial na transação que
permite a execução de todos os comandos após ter existido um rollback, restaurando o estado da
transação para o estado atual no save point. Para criar um save point, basta introduzir o seguinte
comando:
SAVEPOINT savepoint_name
Desta forma é então possível estabelecer um save point. Para se retornar ao estado atual
num save point, é necessário invocar comandos de rollback, que podem seguir as seguintes
definições:
ROLLBACK [ WORK | TRANSACTION ]
ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] savepoint_name
A primeira opção restaura o sistema todo, ou seja, volta para o início da transação,
anulando todas as operações efetuadas. A segunda efetua um rollback para um determinado save
point. A seguir um exemplo concreto bem como os resultados de operações com save points e
rollbacks:
create table test (id integer, primary key (id));
commit;
5
BANCO DE DADOS II
Prof. Ricardo Rodrigues Barcelar
http://www.ricardobarcelar.com.br
insert into test values (1);
commit;
insert into test values (2);
savepoint y;
delete from test;
select * from test; //nada é mostrado
rollback to y;
select * from test; //são mostrados os valores 1 e 2
rollback;
select * from test; // é mostrado o valor 1
6
Download

Aula 13 - Transações de BD