.. .. META INFORMATION OF TRANSLATION .. .. $TranslationStatus: Done, waiting for revision $ .. $OriginalRevision: 11332 $ .. $TranslationAuthors: Robson Mendonça $ .. .. INFO OF THIS FILE (DO NOT EDIT! UPDATED BY SUBVERSION) .. .. $HeadURL: http://django-l10n-portuguese.googlecode.com/svn/branches/docs-1.0.X/topics/db/transactions.txt $ .. $LastChangedRevision: 513 $ .. $LastChangedBy: robsonmwoc $ .. $LastChangedDate: 2009-08-01 20:37:53 -0300 (Sat, 01 Aug 2009) $ .. .. _topics-db-transactions: ======================================== Gerenciando transações de banco de dados ======================================== O Django dá a você poucos caminhos para controlar como as transações de banco de dados são gerenciadas, isso se você estiver usando um banco de dados que suporta transações. Comportamento padrão de transações com Django ============================================= O comportamento padrão do Django é executar com uma transação aberta que ele comita automaticamente quando quaisquer função interna que modifique a base de dados for chamada. Por exemplo, se você chamar ``model.save()`` ou ``model.delete()``, a mudança vai ser realizada imediatamente. Isso parece muito com a configuração auto-commit para a maioria dos bancos de dados. Tão logo você performe uma ação que precisa escrever no banco de dados, o Django produz um comando ``INSERT``/``UPDATE``/``DELETE`` e então faz um ``COMMIT``. Não há ``ROLLBACK`` implícito. Amarrando transações às requisições HTTP ======================================== A forma recomendada de lidar com transações em requisições Web é amarrá-las às fases requisição/resposta através do ``TransactionMiddleware`` do Django. Funciona assim: quando uma requisição é iniciada, o Django começa uma transação. Se a resposta é produzida sem problemas, o Django commita quaisquer transações pendentes. Se a função view produz uma exceção, o Django faz um rollback de quaisquer transações pendentes. Para ativar esta funcionalidade, apenas adicione o ``TransactionMiddleware`` middleware nos eu setting ``MIDDLEWARE_CLASSES``:: MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.cache.CacheMiddleware', 'django.middleware.transaction.TransactionMiddleware', ) A ordem é bastante importante. O middleware de transação se aplica não somente às funções da view, mas também a todos os módulos middleware que que vem após o mesmo. Então, se você usar o session middleware após o transaction middleware, a criação de sessões será parte da transação. Uma exceção a isso seria o ``CacheMiddleware``, que nunca é afetado. O cache middleware usa seu próprio cursor de banco de dados (que é mapeado para a sua própria conexão de banco de dados internamente). Controlando o gerenciamento de transações direto nas views ========================================================== Para a maioria das pessoas, transações baseadas em requisições funciona maravilhosamente bem. Contudo, se você precisa de um controle mais fino sobre como suas transações são gerenciadas, você pode usar os decoradores do Python para mudar a forma como as transações são lidadas por uma função view em particular. .. note:: Mesmo os exemplos abaixo usando funções de view como exemplo, esses decoradores também podem ser aplicados para funções que não view. ``django.db.transaction.autocommit`` ------------------------------------ Use o decorador ``autocommit`` para mudar o comportamento padrão de commit de uma view, independente da configuração global das transações. Exemplo:: from django.db import transaction @transaction.autocommit def viewfunc(request): .... Dentro de ``viewfunc()``, transações serão commitadas quão logo você chame ``model.save()``, ``model.delete()``, ou qualquer outra função que escreva na base de dados. ``django.db.transaction.commit_on_success`` ------------------------------------------- Utilize o decorador ``commit_on_success`` para usar transações únicas para todo o trabalho feito em uma função:: from django.db import transaction @transaction.commit_on_success def viewfunc(request): .... Se a função retorna com sucesso, então o Django irá commitar todo o trabalho feito na função até aquele ponto. Se a função levanta uma exceção, todavia, o Django irá fazer um rollback na transação. ``django.db.transaction.commit_manually`` ----------------------------------------- Use o decorador ``commit_manually`` se você precisa de um controle completo sobre as transações. Ele diz ao Django que você mesmo irá gerenciar a trasação. Se seu view muda o dado e não executa um ``commit()`` ou ``rollback()``, o Django irá lançar uma exceção ``TransactionManagementError``. Gerenciamento manual de transações parece com isso:: from django.db import transaction @transaction.commit_manually def viewfunc(request): ... # Você pode comitar/retroceder quando e onde quiser. transaction.commit() ... # Mas terá de lembrar de fazê-lo você mesmo! try: ... except: transaction.rollback() else: transaction.commit() .. admonition:: Uma nota importante para usuários de versões anteriores do Django: Os métodos de banco de dados ``connection.commit()`` e ``connection.rollback()`` (chamados ``db.commit()`` e ``db.rollback`` na versão 0.91 e anteriores) não existem mais. Eles foram substituídos por ``transation.commit()`` e ``transation.rollback()``. Como desativar globalmente o gerenciamentod e transações ======================================================== Controladores obsecados, podem disabilitar totalmente todo gerenciamento de transações Control freaks can totally disable all transaction management by setting ``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file. Se você fizer isso, o Django não irá prover qualquer gerenciamento de transação automático qualquer. O middleware não irá implicitamente comitar as transações, e você precisará gerenciar os rollbacks. Isto requer que você mesmo comita as alterações feitas pelo middleware e algo a mais. Deste modo, é melhor usar isto em situações onde você precisa rodar o seu próprio middleware de controle de transações ou fazer algo realmente estranho. Em quase todas as situações, você se dará melhor usando o comportamento padrão, ou o middleware, e somente modificar as funções selecionadas caso precise. .. _topics-db-transactions-savepoints: Savepoints ========== Um savepoint é um marcador dentro de uma trasação que habilida você a retornar parte de uma transação, ao invés de toda ela. Os savepoints estão disponíveis para backends PostgreSQL 8 e Oracle. Outros backends proverão funções savepoint, mas eles são operações vazias - eles na verdade não fazem nada. Os savepoints não são usuais especialmente se você estiver usando o comportamento padrão ``autocommit`` do Django. Entretanto, se você estiver usando ``commit_on_success`` ou ``commit_manually``, cada transação aberta construirá uma série de operações de banco de dados, que aguardarão um commit ou um rollback. Se você emitir um rollback, a transação inteira é retrocedida. Os savepoints fornecem um habilidade de executar rollbacks com granularidade fina, ao invés de um rollback completo que poderia ser executada pelo ``transaction.rollback()``. Os savepoints são controlados por três métodos do objeto transação: .. method:: transaction.savepoint() Cria um novo savepoint. Este marca um ponto na transação que é tido como um "bom" estado. Retorna o ID do savepoint (sid). .. method:: transaction.savepoint_commit(sid) Atualiza o savepoint para incluir quaisquer operações que tenham sido executadas desde que o savepoint foi criado, ou desde o último commit. .. method:: transaction.savepoint_rollback(sid) Retrocede a transação para o último ponto em que o savepoint foi commitado. O exemplo a seguir demonstra o uso de savepoints:: from django.db import transaction @transaction.commit_manually def viewfunc(request): a.save() # abre a transação agora contentdo a.save() sid = transaction.savepoint() b.save() # abre a transação agora contendo a.save() e b.save() if want_to_keep_b: transaction.savepoint_commit(sid) # abre a transação que ainda contém a.save() e b.save() else: transaction.savepoint_rollback(sid) # abre a transação agora contendo somente a.save() transaction.commit() Transações no MySQL =================== Se você estiver usando o MySQL, suas tabelas podem ou não suportar transações; isto depende da versão do MySQL e do tipo de tabelas que você está usando. (Para "tipo de tabela," significa algo como "InnoDB" ou "MyISAM".) As peculiaridades de transações no MySQL são fora do escopo do artigo, mas o site do MySQL tem `informações sobre as transações no MySQL`_. Se sua instalação do MySQL *não* suporta transações, então o Django irá funcionar no modo auto-comit: As consultas serão executadas e comitadas logo que forem chamadas. Se sua instalação do MySQL *suporta* transações, o Django irá manipular as transações como explicado neste documento. .. _informações sobre as transações no MySQL: http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html Manipulando exceções em transações do PostgreSQL ================================================ Quando uma chamada para um cursor do PostgreSQL lança uma exceção (tipicamente ``IntegrityError``), todo o SQL subsequente na mesma transação irá falhar com o o erro "current transation is aborted, queries ignored until end of transation block", ou seja, "a transação atual foi abortada, consultas ignoradas até o final do bloco da transação". Embora seja improvável que o uso de um simples ``save()`` gere uma exceção no POstgreSQL, há outros usos mais avançados que podem, como o de salvar objetos com campos únicos, salvando usando o flag force_insert/force_update, ou invocando uma SQL customizada. Há várias maneiras de se deparar com este tipo de erro. Rollback de transações ---------------------- A primeira opção é retroceder toda a transação. Por exemplo:: a.save() # Sucesso, mas pode ser desfeita com rollback de transação try: b.save() # Could throw exception except IntegrityError: transaction.rollback() c.save() # sucesso, mas a.save() pode ter sido desfeita Chamando ``transation.rollback()`` retrocederá toda a transação. Qualquer operação de banco de dados não comitada será perdida. Neste exemplo, as mudanças feitas pelo ``a.save()`` poderiam ser perdidas, mesmo que a operação não gere um erro por si só. Rollback de savepoints ---------------------- Se você está usando o PostgreSQL 8 ou superior, você pode usar :ref:`savepoints ` para controlar a extensão do rollback. Antes de realizar uma operação de banco de dados que possa falhar, você pode setar ou atualizar o savepoint; dessa forma, se a operação falhar, você pode retroceder uma única operação, ao invés de toda transação. Por exemplo:: a.save() # Sucesso, e nunca será desfeita pelo rollback do savepoint try: sid = transaction.savepoint() b.save() # Poderia lançar uma exceção transaction.savepoint_commit(sid) except IntegrityError: transaction.savepoint_rollback(sid) c.save() # Sucesso, e a.save() não será desfeita Neste exemplo, ``a.save()`` não será desfeito no caso de ``b.save()`` lançar uma exceção.