VB.NET 2005 - Usando transações em atualizações de tabelas
Conhece a regra de ouro para atualizações de múltiplas tabelas em um processo ? Se você não conhece vai conhecer agora, a regra diz o seguinte : "Todas as atualizações realizadas em um único processo que afetam mais de uma tabela deverão estar sobre o controle de uma transação"
Pois é, vivendo e aprendendo.... E olha que não é a primeira vez que eu trato deste assunto em meus artigos. Para detalhes siga o link abaixo:
Indo diretamente ao assunto este artigo irá mostrar como usar transações em atualizações de tabelas no SQL Server 2005 fazendo, quando pertinente um paralelo com a ADO, assim se você esta migrando vai perceber que não há nada de novo debaixo deste céu...
Como irei fazer o acesso a uma base de dados SQL Server estarei usando o namespace System.Data.SqlClient e os provedores e objetos relacionados. Desta forma temos que o objeto SqlTransaction possibilita a habilidade de confirmar(commit) ou , em caso de uma exceção, cancelar (rollback) as atualizações que seriam realizadas durante o processo nas tabelas de uma fonte de dados do SQL Server.
Trabalhar com transações ADO.NET é muito parecido com os objetos fornecidos pela ADO em ADODB.Connection, os quais também incluem os métodos : BeginTrans, CommitTrans e RollBackTrans.
A ADO.NET fornece os seguintes métodos correspondentes no objeto SqlTransaction : BeginTransaction, CommitTransaction e RollBackTransaction.
Nota: A ADO.NET permite que você seletivamente alistar comandos em um transação ativa. A ADO não suporta este recurso.
A execução de uma transação ADO.NET pode ser dividida nas seguintes etapas:
Um trecho de código relacionado com as etapas descritas poderia ser escrito assim:
Private Shared Sub Teste() 'define a conexão Dim con As SqlConnection = New SqlConnection("sua string de conexão") 'define o objeto SqlTransaction Dim transaction As SqlTransaction con.Open 'Inicia a Transação transaction = con.BeginTransaction Try 'relaciona os comandos e executa-os call (New SqlCommand("INSERT INTO Tabela1 " + "(Texto) VALUES ('teste1');", con, transaction)).ExecuteNonQuery call (New SqlCommand("INSERT INTO Tabela1 " + "(Texto) VALUES ('teste2');", con, transaction)).ExecuteNonQuery call (New SqlCommand("INSERT INTO Tabela2 VALUES " + "('A', 'B', 'C');", con, transaction)).ExecuteNonQuery 'efetua o commit e confirma as alterações transaction.Commit Catch sqlError As SqlException 'se ocorreu uma exceção desfaz as alterações transaction.Rollback End Try con.Close End Sub |
Existe um conceito que as transações suportam que é conhecido por nível de isolamento (isolation level). Um nível de isolamento representa uma estratégia particular de bloqueio empregada no sistema de banco de dados para melhorar a consistência dos dados. Quanto maior o nível de isolamento mais complexo a estratégia de bloqueio usada.
Assim, um nível de isolamento fornecido pelo banco de dados determina se uma transação irá encontrar comportamentos definidos na consistência dos dados.
A tabela abaixo relaciona os enumerações para os níveis de isolamento da ADO.NET(IsolationLevel) e da ADO(IsolationLevelEnum) traçando um paralelo entre as duas:
ADO.NET | ADODB | ADO.NET - Descrição |
Chaos | AdXactChaos | Previne as mudanças pendentes das transações de maior isolamento de serem sobrescritas |
ReadCommitted | AdXactReadCommitted | Evita os dirty reads mas permite non-repeatable e linhas fantasmas. |
ReadUncommitted | AdXactReadUncommitted | Permite os dirty reads, linhas non-repetable e phantom rows (linhas fantasmas) |
RepeatableRead | AdXactRepeatableRead | Evita non-repeatable reads mas permite phantom rows (linhas fantasmas) |
Serializable | AdXactSerializable | Previne os dirty reads, non-repeatable reads e phantom rows pela colocação de um intervalo de bloqueio nos dados que estão sendo atualizados. |
SnapShot | --- não possui -- | Armazena a versão dos dados do SQL Server que os clientes podem ler quando outro cliente modifica os mesmos dados. |
Unspecified | AdXactUnspecified | Indica que o provedor esta usando um nível de isolamento desconhecido. |
Nota: As definições listadas a seguir ajudam a entender alguns do termos usados na tabela acima: (forma baseados no artigo: http://www.linhadecodigo.com.br/artigos.asp?id_ac=666 de autoria de Thiago Pastorello)
Obs: O nível de isolamento SnapShot é novo na ADO.NET e é suportado somente pelo SQL Server 2005.
Vejamos a seguir um exemplo completo feito no VB 2005 Express onde estamos reutilizando uma única SqlTransaction e SqlCommand para definir as atualizações nas tabelas Clientes e Estados do banco de dados Cadastro.mdf (Este banco de dados foi criado no SQL Server 2005, leia o artigo - VB.NET 2005 - Criando Objetos Básicos de dados. - que mostra as etapas para efetua a tarefa)
Crie um novo projeto no VB 2005 com o nome de transacoesNet e inclua no formulário padrão form1.vb um componente DataGridView e um botão de comando.
Ao executar o projeto iremos carregar o DataGridView com os dados da tabela Clientes do banco de dados Cadastro.mdf. O namespace usado neste projeto é :
Imports System.Data.SqlClient
A string de conexão com o banco de dados usada será armazenada usando o recurso My.Settings conforme os seguintes passos:
O código para efetuar estar tarefa é feita pela rotina carregaDataGridView exibida a seguir:
Private Sub carregaDataGridView() Dim conCadastro As SqlConnection = New SqlConnection(My.Settings.connSQL) Try Dim strSql As String = "SELECT Codigo,Nome,Cidade, Estado FROM Clientes" Dim cmdGrid As New SqlCommand(strSql, conCadastro) cmdGrid.CommandType = CommandType.Text conCadastro.Open() Dim sdrGrid As SqlDataReader = cmdGrid.ExecuteReader Dim intCol As Integer With drGrid If .HasRows Then dgvTransacao.Rows.Clear() For intCol = 0 To .FieldCount - 1 dgvTransacao.Columns.Add(.GetName(intCol), .GetName(intCol)) Next dgvTransacao.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.ColumnHeader While .Read Dim objCells(intCol) As Object .GetValues(objCells) dgvTransacao.Rows.Add(objCells) End While .Close() End If End With Catch ex As Exception MsgBox(ex.Message) Finally conCadastro.Close() End Try End Sub |
A rotina acima é chamada no evento Load do formulário: carregaDataGridView()
O botão de comando é responsável por chamar a rotina executaTransacao() que irá iniciar a transação que irá efetuar operações de Insert e Delete nas tabelas Clientes e Estados. Efetuamos um Commit nas operações e no final se houve alguma exceção damos um RollBack na transação desfazendo as operações feitas.
A seguir o código da rotina executaTransacao:
Public Sub executaTransacao()'Inclue e exclui novo cliente e estado nas tabelas Clientes e Estado Dim conCadastro As SqlConnection = New SqlConnection(My.Settings.connSQL) 'Especifica um objeto para a transação local Dim tranClientesEstado As SqlTransaction = Nothing Dim registrosAfetados As Integer Dim transacaoSQL As String = Nothing Try conCadastro.Open() Try 'Inicia a transação
tranClientesEstado = conCadastro.BeginTransaction(IsolationLevel.RepeatableRead) 'Define e execurta a instrução INSERT usando SqlCommand para um novo cliente transacaoSQL = "INSERT "Dim strSQL As String = "INSERT Clientes (Nome ,Endereco, Cidade, Estado, Email, Nascimento) VALUES ('Macoratti','Rua Projetada, 20','Lins','SP','macoratti@yahoo.com','09/09/1978')" Dim cmdTrans As SqlCommand = New SqlCommand(strSQL, conCadastro) cmdTrans.CommandType = CommandType.Text
cmdTrans.Transaction = tranClientesEstado registrosAfetados = cmdTrans.ExecuteNonQuery
strSQL = "INSERT Estados (NomeEstado, SiglaEstado) VALUES ('Rio Grande do Sul','RS')"cmdTrans.CommandText = strSQL
registrosAfetados += cmdTrans.ExecuteNonQuery tranClientesEstado.Commit() 'Exibe no DataGridView carregaDataGridView() Application.DoEvents()
MsgBox( "Clique em OK para continuar com a transação...")
transacaoSQL = "DELETE "
tranClientesEstado = conCadastro.BeginTransaction(IsolationLevel.RepeatableRead) strSQL = "DELETE FROM Clientes WHERE Codigo = 25"cmdTrans.CommandText = strSQL
cmdTrans.Transaction = tranClientesEstado
registrosAfetados += cmdTrans.ExecuteNonQuery ' Para efetuar testes o critério códigoEstado deve ser referido a um registro existente , verifique a tabela antes de informar strSQL = "DELETE FROM Estados WHERE CodigoEstado = 18"cmdTrans.CommandText = strSQL registrosAfetados += cmdTrans.ExecuteNonQuery 'Da um Commit na transação que usa o DELETE tranClientesEstado.Commit()
carregaDataGridView() Catch excTrans As SqlExceptionMsgBox(excTrans.Message + excTrans.StackTrace, , transacaoSQL + " Transação falhou") Try' cancela as operações realizadas tranClientesEstado.Rollback() Catch excRollback As SqlExceptionMsgBox(excTrans.Message + excTrans.StackTrace, , transacaoSQL + " Rollback Falhou")End Try End Try Catch ex As Exception MsgBox(ex.Message + ex.StackTrace) Finally'Fecha a conexao SqlConnection sempre conCadastro.Close() Dim strMsg As String If registrosAfetados = 4 Then strMsg = "Transações INSERT e DELETE realizadas com sucesso."Else strMsg = "As Transações INSERT e/ou DELETE falharam. " + " Verifique as tabelas..."End If End Try End Sub |
A rotina acima é chamada no evento Click do botão de comando: executaTransacao()
Executando o projeto temos a janela abaixo antes da execução da transação:
Após executar a transação temos na figura abaixo o registro que foi incluído e o registro 25 que foi excluído , confirmando que a transação foi executada com sucesso. Se verificarmos a tabela Estados veremos também o registro incluído.
Deve ficar bem claro que este é apenas um exemplo visto que em ambiente de produção seriam usadas stored procedures T-SQL BEGIN TRAN[SACTION], COMMIT TRAN[SACTION] e ROLLBACK TRAN[SACTION] para gerencia múltiplas atualizações.
Bom estudo e até o próximo artigo VB.NET
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
|
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#