ADO - Usando Transações - BeginTrans, CommitTrans e RollBack.


Os conceitos básicos sobre transações já foram estudados no artigo O Processamento de Transações: BeginTrans, CommitTrans e RollBack. Neste breve artigo iremos mostrar como usar as transações com a tecnologia ADO.

O projeto básico consiste de um único formulário mostrado a seguir:

Neste Projeto Temos os seguintes Controles:
  • Dois Controles ListView , nomeados como : Listfrom e Listto.
  • Um Controle MaskEdBox - nomeado como - Maskvalor.
  • Dois botões de Comandos , nomeados : Command1 ( o botão Transferir ) e Command2 ( o botão Encerrar)

O banco de dados que utilizamos é o Nwind.mdb que vem junto com o Visual Basic . Criamos uma tabela(veja como fazer isto em : Criando um banco de dados e uma tabela para armazenar suas informações) chamada contas neste banco de dados com a seguinte estrutura:

A tabela contas que criamos no banco de dados Nwind.mdb e que copiamos para o diretório c:\teste.

Como funciona o projeto

O projeto funciona da seguinte maneira:

  1. Na abertura do projeto em tempo de execução , no evento Form_Load os controles ListView são preenchidos com os dados das tabela contas
  2. Voce deve selecionar uma conta em origem , informar o valor da transferência e a seguir selecionar uma conta em destino.
  3. Após feita a seleção das contas e informar o valor , clique no botão Transferir , uma mensagem irá solicitar a confirmação da transação .
  4. Na confirmação a conta de origem e debitada e a de destino creditada. (Obs: Não é possível transferencias para a mesma conta.)

Vejamos o projeto em tempo de execução :

O Código do projeto segue abaixo:

Option Explicit
Private mConn As Connection
Private Sub Command1_Click()
    Dim lRowsAffected As Long
    Dim sError As String
    Dim sCmd As String
    Dim rs As Recordset

    If vbYes = MsgBox("Transferir   " _
       & Format(Val(maskvalor.Text), "$#,##0.00;($#,##0.00)") _
       & "   De ->   " & listfrom.SelectedItem.Text _
       & "   Para ->  " & listto.SelectedItem.Text & ".", vbYesNo) Then

        'iniciando a transação
        mConn.BeginTrans
        On Error GoTo TransferFailure

       'usar o método execute do objeto Connection
        sCmd = "UPDATE contas"
        sCmd = sCmd & " SET saldo = saldo - " & CCur(maskvalor.Text)
        ' atualize somente se a conta de origem tiver saldo suficiente
        sCmd = sCmd & " WHERE saldo >= " & CCur(maskvalor.Text)
        sCmd = sCmd & " AND AccountId = " _
               & Right(listfrom.SelectedItem.Key _
               , Len(listfrom.SelectedItem.Key) - 1)
        
        mConn.Execute sCmd, lRowsAffected, adExecuteNoRecords
        
        If lRowsAffected = 0 Then
            sError = " Saldo insuficiente para realizar transferência..."
            GoTo TransferFailure
        End If

       'ou use os métodos do objeto recordset
        Set rs = New Recordset
        rs.Open "SELECT * FROM contas WHERE AccountId = " _
            & Right(listto.SelectedItem.Key _
            , Len(listto.SelectedItem.Key) - 1), mConn, _
            adOpenDynamic, adLockPessimistic
        rs!saldo = rs("saldo") + Val(maskvalor.Text)
        rs.Update
        'parece que tudo ocorreu bem , vamos salvar(commit) a transação
        mConn.CommitTrans
        rs.Close
    End If


TransferDone:
    'deu tudo certo então atualiza os controles listview
    On Error GoTo 0
    Set rs = Nothing
    RefreshLists
    Exit Sub

TransferFailure:
    'alguma coisa deu errado , vamos cancelar(rollback) a transação
    mConn.RollbackTrans
    Dim ADOError As Error
    For Each ADOError In mConn.Errors
        sError = sError & ADOError.Number & " - " & _
             ADOError.Description & vbCrLf
    Next ADOError
    MsgBox sError

End Sub
Private Sub Command2_Click()
  Unload Me
End Sub
Private Sub Form_Activate()
    maskvalor.SetFocus
End Sub
Private Sub Form_Load()
    'Abrindo uma conexão
    Set mConn = New Connection
    mConn.Open "Provider=Microsoft.Jet.OLEDB.3.51;Data Source=c:\teste\nwind.mdb"
    RefreshLists
End Sub
Private Sub Form_Unload(Cancel As Integer)
    mConn.Close
    Set mConn = Nothing
End Sub
Private Sub RefreshLists()
    'atualizando os controles com os saldos
    Dim NewItem As ListItem
    Dim rs As Recordset
    Set rs = New Recordset
    listfrom.ListItems.Clear
    listto.ListItems.Clear
    rs.Open "contas", mConn, adOpenForwardOnly, adLockReadOnly

    Do Until rs.EOF
        Set NewItem = listfrom.ListItems.Add(, "k" & rs("AccountId"), rs("Name"))
        NewItem.SubItems(1) = Format(rs("saldo"), "$0.00")
        Set NewItem = listto.ListItems.Add(, "k" & rs("AccountId"), rs("Name"))
        NewItem.SubItems(1) = Format(rs("saldo"), "$0.00")
        rs.MoveNext
    Loop
    
    rs.Close
    Set rs = Nothing
End Sub
Private Sub maskvalor_GotFocus()
  maskvalor.SelStart = 0
  maskvalor.SelLength = Len(maskvalor.Text)
End Sub
Private Sub maskvalor_KeyPress(KeyAscii As Integer)
  Select Case KeyAscii
    Case 8, 48 To 57, 127
    Case 46
       KeyAscii = 44
    Case 13
      'Simula o pressionamento da tecla TAB
      SendKeys "{tab}"
      'A linha a seguir evita ouvir um bip
      KeyAscii = 0
    Case Else
       KeyAscii = 0
  End Select
End Sub

Observe que usamos dois métodos da ADO para atualizar os dados:

Usando SQL - instrução UPDATE e o método Execute

sCmd = "UPDATE contas"
sCmd = sCmd & " SET saldo = saldo - " & CCur(maskvalor.Text)
'atualize somente se a conta de origem tiver saldo suficiente
sCmd = sCmd & " WHERE saldo >= " & CCur(maskvalor.Text)
sCmd = sCmd & " AND AccountId = " _
& Right(listfrom.SelectedItem.Key _
, Len(listfrom.SelectedItem.Key) - 1)
        
mConn.Execute sCmd, lRowsAffected, adExecuteNoRecords

Usando o método Update da ADO

Set rs = New Recordset
rs.Open "SELECT * FROM contas WHERE AccountId = " _
& Right(listto.SelectedItem.Key _
, Len(listto.SelectedItem.Key) - 1), mConn, _
adOpenDynamic, adLockPessimistic
rs!saldo = rs("saldo") + Val(maskvalor.Text)
rs.Update

A rotina que atualiza os controles de lista(ListView) é:

    Do Until rs.EOF
        Set NewItem = listfrom.ListItems.Add(, "k" & rs("AccountId"), rs("Name"))
        NewItem.SubItems(1) = Format(rs("saldo"), "$0.00")
        Set NewItem = listto.ListItems.Add(, "k" & rs("AccountId"), rs("Name"))
        NewItem.SubItems(1) = Format(rs("saldo"), "$0.00")
        rs.MoveNext
    Loop

Os métodos : BeginTrans , CommitTrans e RollBack estão destacados no código.

Bem , acho que é só isto . Legal este projeto né.. ? 

Você  pode  recortar e copiar a vontade.

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:


José Carlos Macoratti