O MySQL Server (versão 3.23-max e todas as versões 4.0 e
acima) suportam transações com os mecanismos de
armazenamento transacionais
InnoDB
e BDB
.
InnoDB
fornece compatibilidade
total com ACID
. See
Capítulo 7, Tipos de Tabela do MySQL.
Os outros tipos de tabelas não transacionais (tais como
MyISAM
) no MySQL Server seguem um paradigma
diferente para integridade de dados chamado
``Operções Atômicas
.'' Em termos de
transação, tabelas MyISAM
efetivamente
sempre operam em modo AUTOCOMMIT=1
.
Operações atômicas geralmente oferecem integridade
comparável com a mais alta performance.
Com o MySQL Server suportando ambos os paradigmas, o usuário pode decidir se precisa da velocidade das operações atômicas ou se precisa usar recursos transacionais em seu aplicativo. Esta escolha pode ser feita em uma base por tabela.
Como notado, a comparação para tabelas transacionais vs.
não transacionais As noted, the trade off for transactional
vs. non-transactional table se encontra em grande parte no
desempenho. Tabelas transacionais tem uma exigência de
memória e espaço em disco significantemente maior e maior
sobrecarga da CPU. Tipos de tabelas transacionais como
InnoDB
oferecem muitos recursos únicos. O
projeto modular do MySQL Server permite o uso concorrente de
todas estes mecanismos de armazenamento para servir a
diferentes exigências e oferecer um ótimo desempenho em
todas as situações.
Mas como fazer uso dos recursos do MySQL Server para manter
uma integridade rigorosa mesmo com tabelas
MyISAM
não transacionais e como este
recurso se compara com os tipos de tabelas transacionais?
No paradigma transacional, se as suas aplicações são
escritas de uma forma que é dependente na chamada de
ROLLBACK
em vez de
COMMIT
em situações críticas, então
transações são mais convenientes. Além disso,
transações asseguram que atualizações inacabadas ou
atividades corrompidas não sejam executadas no banco de
dados; o servidor oferece uma oportunidade para fazer um
rollback automático e seu banco de dados é mantido.
O MySQL Server, na maioria dos casos, permite a você resolver potenciais problemas incluindo simples conferências antes das atualizações e executando scripts simples que conferem inconsistências no banco de dados e, automaticamente, repara ou avisa caso isto ocorra. Perceba que apenas usando o log do MySQL ou mesmo adicionando um log extra, pode-se corrigir tabelas perfeitamente sem nenhuma perda de integridade.
Mais do que nunco, atualizações transacionais fatais
podem ser reescritas para serem atômicas. De fato podemos
dizer que todos problemas de integridade que transações
resolvem podem ser feitas com LOCK
TABLES
ou atualizações atômicas, assegurando
que você nunca irá ter uma finalização automática da
tabela, o que é um problema comum em bancos de dados
transacionais.
Nem mesmo transações podem prevenir todas as falhas se o servidor cair. Nestes casos mesmo um sistema transacional pode perder dados. A diferença entre sistemas diferentes é apenas em quão pequeno é o lapso de tempo em que eles podem perder dados. Nenhum sistema é 100% seguro, somente ``seguro o suficiente.'' Mesmo o Oracle, com reputação de ser o mais seguro bancos de dados transacionais, tem relatos de algumas vezes perder dados nestas situações.
Para estar seguro com o MySQL Server, você apenas deve fazer backups e ter o log de atualizações ligado. Com isto você pode se recuperar de qualquer situação possível com bancos de dados transacionais. É sempre bom ter backups, independente de qual banco de dados você usa.
O paradigma transacional tem seus benefícios e suas desvantagens. Muitos usuários e desenvolvedores de aplicações dependem da facilidade com a qual eles podem codificar contornando problemas onde abortar parece ser, ou é necessário. No entanto, se você é novo no paradigma de operações atômicas ou tem mais familiaridade ou conforto com transações, considere o benefício da velocidade que as tabelas não transacionais podem oferece, na ordem de 3 a 5 vezes da velocidade que as tabelas transacionais mais rápidas e otimizadas.
Em situações onde integridade é de grande importância, as
atuais características do MySQL permitem níveis
transacionais ou melhor confiança e integridade. Se você
bloquear tabelas com LOCK TABLES
todos as
atualizações irão ser adiadas até qualquer verificação
de integridade ser feita. Se você só obter um bloqueio de
leitura (oposto ao bloqueio de escrita), então leituras e
inserções poderão ocorrer. Os novos registros inseridos
não poderão ser visualizados por nenhum dos clientes que
tiverem um bloqueio de LEITURA
até eles
liberarem estes bloqueios. Com INSERT
DELAYED
você pode enfileirar inserções em uma
fila local, até os bloqueios serem liberados, sem que o
cliente precise esperar atá a inserção completar. See
Secção 6.4.3.2, “Sintaxe INSERT DELAYED
”.
``Atômico'', no sentido em que nós mencionamos, não é mágico. Significa apenas que você pode estar certo que enquanto cada atualização específica está sendo executada, nenhum outro usuário pode interferir com ela, e nunca haverá um rollback automático (que pode acontecer em sistemas baseados em transações se você não tiver muito cuidado). O MySQL também assegura que nunca ocorrerá uma leitura suja.
A seguir estão algumas técnicas para trabalhar com tabelas não transacionais:
Loops que precisam de transações normalmente pode ser
codificados com a ajuda de LOCK TABLES
,
e você não precisa de cursores para atualizar regitros
imeditamente.
Para evitar o uso do ROLLBACK
, você
pode usar as seguintes estratégias:
Use LOCK TABLES ...
para fazer um
lock todas as tabelas que você quer acessar.
Condições de teste.
Atualize se estiver tudo OK.
Use UNLOCK TABLES
para liberar seus
locks.
Isto é normalmente um método muito mais rápido que usar
transações com possíveis ROLLBACK
s,
mas nem sempre. A única situação que esta solução
não pode tratar é quando alguém mata a threads no meio
de uma atualização. Neste caso, todas os locks serão
liberados mas algumas das atualização podem não ter
sido execuadas.
Você também pode usar funções para atualizar registros em uma única operação. Você pode conseguir uma aplicação muito eficiente usando as seguintes técnicas:
Modifique campos em relação ao seus valores atuais.
Atualize apenas aqueles campos que realmente tiveram alterações.
Por exemplo, quando fazemos atualizações em alguma
informação de cliente, atualizamoa apenas os dados do
clientes que alteraram e testamos apenas aqueles com dados
alterados ou dados que dependem dos dados alterados,
mudaram em comparação com o registro original. O teste
dos dados alterados é feito com a cláusula
WHERE
na instrução
UPDATE
. Se o registro não foi
atualizado, mandamos ao cliente uma mensagem: ''Some of
the data you have changed has been changed by another
user.'' Então mostramos o registro antigo versus o novo
em uma janela, assim o usuário pode decidir qual versão
do registro de cliente de ser usado.
Isto nos dá algo similar a lock de colunas mas que, na
verdade, é melhor porque apenas atualizamos algumas das
colunas, usando valores relativos ao seu valor atual. Isto
significa que instruções UPDATE
comuns se parecem com estas:
UPDATE nometabela SET pay_back=pay_back+125; UPDATE customer SET customer_date='current_date', address='new address', phone='new phone', money_he_owes_us=money_he_owes_us-125 WHERE customer_id=id AND address='old address' AND phone='old phone';
Como você pode ver, isto é muito eficiente e funciona
mesmo se outro cliente alterar os valores nas colunas
pay_back
ou
money_he_owes_us
.
Em muitos casos, usuários querem fazer
ROLLBACK
e/ou LOCK
TABLES
com o propósito de gerenciarem
identificadores únicos para algumas tabelas. Isto pode
ser tratado muito mais eficientemente usando uma coluna
AUTO_INCREMENT
e também uma função
SQL LAST_INSERT_ID()
ou a função da
API C mysql_insert_id()
. See
Secção 12.1.3.32, “mysql_insert_id()
”.
Geralmente você pode codificar evitando lock de registro.
Algumas situações realmente precisam disto, e tabelas
InnoDB
suportam lock de regitstro.
Comoo MyISAM, você pode usar uma coluna de flag na tabela
e fazer algo como a seguir:
UPDATE nome_tbl SET row_flag=1 WHERE id=ID;
O MySQL retorna 1 para o número de linhas afetadas se as
linhas foram encontradas e row_flag
já
não era 1 na linha original.
Você pode pensar nisto como se o MySQL Server tivesse alterado a consulta anterior para:
UPDATE nome_tbl SET row_flag=1 WHERE id=ID AND row_flag <> 1;
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.