Nesse post, não pretendo explicar o que é um ORM (SQLObject, Alchemy, Hibernate, etc..), nem o que é uma transação.

Quem sabe em um post futuro… por hora, dexarei ao final deste post alguns links interessantes sobre o assunto. O foco é mostrar como utilizar uma transação com python, usando o sqlobject.

Bom, vamos lá..

def executaTransacao(funcaoCallback, *args):
	from sqlobject import sqlhub
	conexao = [conexao] # Existem varias maneiras de obter uma conexao. Mas se este post lhe interessou, você provavelmente já tem a conexao.. rs
	conn_transacao = conexao.transaction()
	sqlhub.threadConnection = conn_transacao 
 
	try:
		try:
			valor = funcaoCallback(conn_transacao, *args)
		except Exception, ex:
			conn_transacao.rollback()
			raise ex
		else:
			conn_transacao.commit()
			return valor
	finally:
		sqlhub.threadConnection = conexao

linha 2 : Importa o sqlhub
linha 3 : Guardamos a referencia da conexao atual (para obter/abrir uma conexao com o banco, tem um post no site oturbogears.org
linha 4 : Esse método transaction() cria um objeto Transaction, que possui uma cópia da conexão atual, porém com o atributo autoCommit = False
linha 5 : troca a conexão do processo/thread atual pela conexao da transaction
linha 9 : Executa a função de callback* repassando os parâmetros informados na chamada da executaTransacao
linha 11: Caso ocorra qualquer exceção na funcao de callback, qualquer alteração realizada no banco será desfeita (Rollback)*. Porém só funcionará rollback nas alterações do banco onde a conexao da transação foi explicitamente utilizada (vou explicar mais a frente)
linha 12: Levanta a exceção ocorrida para ser tratada.
linha 14: Se nenhuma exceção ocorreu, dá Commit em todas as alterações feitas no banco.
linha 15: Retorna um valor da função de callback (caso queira retornar algo)
linha 17: Depois de tudo, com exceção ou não, devolve a conexao antiga para o processo/thread atual

*Função de Callback: Quando passamos a referência de uma função como parâmetro de outra função.

Já temos nosso método que vai gerênciar a nossa transação, agora podemos escrever nossa função que, efetivamente realiza as alterações no banco de dados.
Para um simples entendimento, vamos criar uma função que grava varias pessoas no banco de dados (tabela pessoa). O número de pessoas é informado como parâmetro.

Considerar que, a tabela pessoa, possui 0 (zero) registros e tem os seguintes campos:   id e nome

def minhaTransacao(connTrans, totalPessoas):
	for pessoa in range(totalPessoas):
		Pessoa(
				nome = "Pessoa %s" % pessoa,
				connection = connTrans
		)
 
                # Altera o nome da pessoa de id 2
                Pessoa.get(2, connTrans).set(nome = "Pessoa 2 editada")
 
                # Altera o nome da pessoa de id 2
                Pessoa.get(30, connTrans).set(nome = "Pessoa 30 editada") 
 
                return "Comandos executados com Sucesso"

linha 1 : Assinatura da função. Obrigatório ter pelo menos 1 parâmetro, que é a conexao da trasansação, recebida da executaTransacao.
linha 2 / 3 : Grava as pessoas no banco de dados (tabela Pessoa), conforme o numero informado no parametro totalPessoas.
Importante: Notem que, ao gravar uma pessoa na tabela, é informado um atributo connection. Isto serve para que esse INSERT seja feito utilizando a transação, sendo assim possível efetuar o commit/rollback. Se essa conexão não fosse explicitada aí, a transação não teria efeito nesse comando.

Utilizando as funções criadas:

retorno = ""
try:
	retorno = executaTransacao(minhaTransacao, 10)
except Exception, ex:
       raise ex
 
print retorno

linha 3 : Executa nossa transação, passando o valor 10

Nesse exemplo acima, acabamos criando um exemplo de ROLLBACK, pois será levantada uma exceção:

A transação efetua as seguintes ações:
(funcao minhatransacao)
– Grava 10 pessoas na tabela pessoa (id de 0 a 9)
– Edita o nome da pessoa com id = 2 de “Pessoa 2” para “Pessoa 2 editada”
– Tenta editar o nome da pessoa com id 30, de “Pessoa 30” para “Pessoa 30 editada”, PORÉM, esse registro não existe, e é levantada uma exceção.
– a funcao executaTransacao detecta a exceção, e desfaz a edição da pessoa com id = 2, de “Pessoa 2 editada” para “Pessoa 2”
– as 10 pessoas que haviam sido inseridas na tabela, são excluídas.
– a exceção então é levantada mais uma vez, para fora da executaTransacao, para possível tratamento… Nesse caso, estamos apenas dando um raise.

Se, neste exemplo, ao invés de passar 10, passassemos 31 ou valor mais alto, a função minhaTransacao teria rodado sem levantar nenhuma exceção, logo, a funcao executaTransacao daria COMMIT , e todos os registros seriam salvos no banco com sucesso.

Bom, então é isso… Espero ter ajudado.

Qualquer dúvida / sugestão, podem deixar nos comentários que procurarei responder o mais breve possível.

Até a próxima!

Exemplo de fluxo de uma transação simples

Exemplo de fluxo de uma transação simples

Links Interessantes:

Manual do SQLObject traduzido para português:
http://oturbogears.org/documentacao/tutorial/tutorial-sqlobject

Object-relational mapping
http://en.wikipedia.org/wiki/Object-relational_mapping

Mapeamento objeto-relacional
http://pt.wikipedia.org/wiki/Orm

PDF sobre Transação
http://www.dcc.ufam.edu.br/~eccv/bd1/slides/3-transacoes.pdf