Clipper On Line • Ver Tópico - SQL - Rollback

SQL - Rollback

Discussão sobre SQL

Moderador: Moderadores

 

SQL - Rollback

Mensagempor leandrolinauer » 30 Jan 2021 12:43

Bom dia a todos.
Estou em andamento com a mudança de DBF para SQL.
Mas já para fazer direitinho, vai aí um pergunta que não localizei resposta no forum.

Gravando os dados.
Tenho 3 tabelas exemplo: PEDIDOS, tenho a tabela PEDIDOS_CABEÇALHO, PEDIDOS_PARCELAS, PEDIDO_ITENS, são três tabelas ou mais ou menos, e tenho que gravar os dados de um pedido gerado venda.
Gravo com insert into nas tres tabelas mas vamos supor que ocorreu um erro quando estava gravando as parcelas, ou seja, tenho gravado o cabeçalho e a parcela 1 e faltou o resto das parcelas e dos itens de pedidos na tabela 3.

Pergunto? como eliminar este erro em SQL?
Estou usando firebird 3.0
Já pesquisei sobre ROLLBACK mas não compreendi para usar neste modelo que necessito.

Grato a todos
Harbour 3.2 + GtWVW + QT + SQLite3 + DBF + SQL (Firebird)
leandrolinauer
Usuário Nível 3

Usuário Nível 3
 
Mensagens: 373
Data de registro: 16 Out 2006 10:59
Cidade/Estado: Paranaíba-MS
Curtiu: 0 vez
Mens.Curtidas: 12 vezes

SQL - Rollback

Mensagempor alxsts » 30 Jan 2021 18:27

Olá!
leandrolinauer escreveu:Já pesquisei sobre ROLLBACK mas não compreendi para usar neste modelo que necessito

ROLLBACK faz parte de um conceito chamado "Transactions" (transações), que existe nos principais bancos de dados relacionais, se não em todos. Para entender um pouco mais sobre o funcionamento, leia o artigo Transação (banco de dados).

Se você está migrando DBF para banco de dados relacional, provavelmente já criou algumas funções em Harbour para rotinas básicas em SQL, como conversão de tipos de dados do banco para Harbour, executar comandos SQL, etc. No código abaixo, supus que você tenha uma função chamada "ExecSQL" para usar na execução de sentenças SQL. Não conheço Firebird. O exemplo é genérico e você precisará adaptá-lo às tuas necessidades e à sintaxe do Firebird. É apenas um ponto de partida, mostrando inclusive a manipulação de erros pelo Harbour.

FUNCTION InserirPedido(...)

   LOCAL lRet := .T., oError

   BEGIN SEQUENCE

      ExecSQL( "BEGIN TRANSACTION;" )  // inicia a transação

      ExecSQL( "INSERT INTO tabela1 ( {lista-de-colunas} VALUES ( {lista-de-valores} ) );" )
      ExecSQL( "INSERT INTO tabela2 ( {lista-de-colunas} VALUES ( {lista-de-valores} ) );" )
      ExecSQL( "INSERT INTO tabela3 ( {lista-de-colunas} VALUES ( {lista-de-valores} ) );" )

      ExecSQL( "COMMIT;" )  // confirma a atualização
   RECOVER USING oError

      Alert( "Não foi possível concluir a inclusão do pedido." + hb_osNewLine +;
             "Erro " + LTrim( Str( oError:genCode ) ) + " / " + oError:description ;
           )
      ExecSQL( "ROLLBACK;" )  // desfaz a atualização
      lRet := .F.

   END SEQUENCE

RETURN lRet


TransactionTransacao
[]´s
Alexandre Santos (AlxSts)
alxsts
Colaborador

Colaborador
 
Mensagens: 2943
Data de registro: 12 Ago 2008 15:50
Cidade/Estado: São Paulo-SP-Brasil
Curtiu: 21 vezes
Mens.Curtidas: 248 vezes

SQL - Rollback

Mensagempor leandrolinauer » 01 Fev 2021 14:48

Boa tarde alxsts.
Sim, realmente já tenho minhas funções adaptadas a partir de exemplos aqui do forum para executar tudo.
O que realmente eu necessitava era um pouco de entendimento a respeito de como gravar dados para não falhar ainda mais quando é em varias tabelas, para não ficar gravado aos pedaços.
Então é realmente o que eu necessitava, saber que o melhor é gravar junto em uma unica transação, e tratar se houver erro de gravação.
Valeu, muito obrigado, vou adaptar para firebird.
Harbour 3.2 + GtWVW + QT + SQLite3 + DBF + SQL (Firebird)
leandrolinauer
Usuário Nível 3

Usuário Nível 3
 
Mensagens: 373
Data de registro: 16 Out 2006 10:59
Cidade/Estado: Paranaíba-MS
Curtiu: 0 vez
Mens.Curtidas: 12 vezes

SQL - Rollback

Mensagempor asimoes » 20 Fev 2021 16:34

Alexandre

Poderia mostrar o código da função ExecSQL ?
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

SQL - Rollback

Mensagempor asimoes » 20 Fev 2021 17:08

Com MariaDB banco que eu uso, transação só consigo usando BeginTrans(), CommitTrans() e RollBackTrans() do objecto da conexão

Essa forma só vendo como funciona a função ExecSQL( "BEGIN TRANSACTION;" )
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

SQL - Rollback

Mensagempor Fernando queiroz » 20 Fev 2021 19:59

asimoes escreveu:Com MariaDB banco que eu uso, transação só consigo usando BeginTrans(), CommitTrans() e RollBackTrans() do objecto da conexão

Essa forma só vendo como funciona a função ExecSQL( "BEGIN TRANSACTION;" )


já que você usa o MARIADB queria uma informação , se você usa ADO ?? ou qual você usa ??

NO caso do MARIADB o COMMIT
A declaração COMMIT encerra uma transação, salvando quaisquer alterações nos dados para que eles se tornem visíveis para transações subsequentes. Além disso, desbloqueia metadados alterados pela transação atual. Se o compromisso automático for definido como 1, um compromisso implícito será realizado após cada declaração. Caso contrário, todas as transações que não terminam com um COMMIT explícito são implicitamente revertidas e as alterações são perdidas. A instrução ROLLBACK pode ser usada para fazer isso explicitamente.

Bom eu não faço o COMMIT e todas as transações são gravadas. ( sera que so funciona automatico no MARIADB ?? )
HARBOUR 3.2, HWGUI 2.23 B3, SEFAZCLASS, PDFClass, ADO + MariaDB/MySQL, RMChart
Fernando queiroz
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 737
Data de registro: 12 Nov 2014 23:41
Cidade/Estado: Porto Alegre/RS
Curtiu: 12 vezes
Mens.Curtidas: 58 vezes

SQL - Rollback

Mensagempor asimoes » 20 Fev 2021 20:05

Uso ADO, e dessa forma que eu uso no Oracle também

Tenho o método para executar as transações:

Usando ::oConexao do método ConexaoOpenMariaDB
METHOD AdoBegin()
LOCAL nCod_ret := 0, oErro

   BEGIN SEQUENCE WITH {| oErro | oErro:cargo := {  oClPF:ListaFuncoes(2, oErro) }, Break( oErro ) }
      ::oConexao:BeginTrans()
      ::__lEndTrans := .F.   
   RECOVER USING oErro
      cErro   := oErro:cargo[1] + Hb_Eol() + Hb_Eol() + ::cMensagemUsuario
      oGuiProc:ScreenErro( "Erro", cErro )
      nCod_ret := 1   
   END

RETURN ( nCod_ret )

METHOD AdoCommit()
LOCAL nCod_ret := 0, oErro

   BEGIN SEQUENCE WITH {| oErro | oErro:cargo := {  oClPF:ListaFuncoes(2, oErro) }, Break( oErro ) }
      ::oConexao:CommitTrans()
      ::__lEndTrans := .T.   // VARIAVEL PRIVATE QUE DEVERÁ SER DECLARADA E INICIALIZADA NO PROGRAMA PRINCIPAL
   RECOVER USING oErro
      cErro   := oErro:cargo[1] + Hb_Eol() + Hb_Eol() + ::cMensagemUsuario
      oGuiProc:ScreenErro( "Erro", cErro )
      nCod_ret := 1
   END

RETURN ( nCod_ret )

METHOD AdoRollBack()
LOCAL nCod_ret := 0, oErro

   BEGIN SEQUENCE WITH {| oErro | oErro:cargo := {  oClPF:ListaFuncoes(2, oErro) }, Break( oErro ) }
      ::oConexao:RollBackTrans()
      ::__lEndTrans := .T.   // VARIAVEL PRIVATE QUE DEVERÁ SER DECLARADA E INICIALIZADA NO PROGRAMA PRINCIPAL
   RECOVER USING oErro
      cErro   := oErro:cargo[1] + Hb_Eol() + Hb_Eol() + ::cMensagemUsuario
      oGuiProc:ScreenErro( "Erro", cErro )
      nCod_ret := 1
   END

RETURN ( nCod_ret )

O método da conexão:
METHOD ConexaoOpenMariaDB()
LOCAL oErro

   BEGIN SEQUENCE WITH {| oErro | oErro:cargo := {  oClPF:ListaFuncoes(2, oErro) }, Break( oErro ) }

      IF ! ::lLocalHost
         IF File( [NETIO\SERVER5\SERVIDORIP.INI] )
            ::cServer := hwg_GetIni( 'CONFIGURACAO', 'Addr', '', [NETIO\SERVER5\SERVIDORIP.INI] )
         ENDIF
      ENDIF
         
      WITH OBJECT ::oConexao := Win_OleCreateObject( "ADODB.Connection" )
         :ConnectionString := iif( win_OsIs10(), "Provider=MSDASQL;", "" )
         :ConnectionString += "Driver={MariaDB ODBC 3.1 Driver};"
         :ConnectionString += ;
                                    "Server=" + ::cServer + ";" + ;
                                    "Port=" + Hb_NtoC( ::nPort ) + ";" + ;
                                    "Stmt=;" + ;
                                    "Database=" + ::cDatabase + ";" + ;
                                    "User=" + ::cUser + ";" + ;
                                    "Password=" + ::cPassword + ";" + ;
                                    "Collation=latin1_swedish_ci;" + ;
                                    "AUTO_RECONNECT=1;" + ;
                                    "COMPRESSED_PROTO=1;" + ;
                                    "PAD_SPACE=1"
         
         :CommandTimeOut    := 600 // seconds
         
         :ConnectionTimeOut := 600 // seconds
         
         :CursorLocation    := adUseClient
         
         :Open()
       
      END
       
   RECOVER USING oErro
      cErro := oErro:cargo[1]
      ::lLocalHost := .T.
      ::cServer    := "LOCALHOST"
      ::ConexaoOpenMariaDB()
   END
     
RETURN Nil
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

SQL - Rollback

Mensagempor asimoes » 20 Fev 2021 20:11

BeginTrans(), CommitTrans() e RollBackTrans() são métodos do objeto ADODB.Connection

O controle de erro você faz da forma como quiser ou deixa estourar pelo errorsys
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

SQL - Rollback

Mensagempor Fernando queiroz » 20 Fev 2021 20:29

ABRINDO A CONECCÃO e testando se conseguiu , caso contrario sai do sistema
   oServer := ::MySqlConnection( cServer, cUser, cPassword, nPort )
   BEGIN SEQUENCE WITH __BreakBlock()
      oServer:Open()
   ENDSEQUENCE
   IF oServer:State != 1
      hwg_MsgInfo( "FALHA NA CONECÇÃO COM O BANCO DE DADOS", "VERIFIQUE!!!")
      QUIT
   endif


rotina de coneccao
METHOD MySqlConnection( cServer, cUser, cPassword, nPort )
LOCAL cnConnection

   cnConnection:= win_OleCreateObject( "ADODB.Connection" )
   cnConnection:ConnectionString := iif( win_OsIs10(), "Provider=MSDASQL;", "" )
   cnConnection:ConnectionString += "Driver={MariaDB ODBC 3.1 Driver};"
   cnConnection:ConnectionString += ;
      "Server=" + cServer + ";" + ;
      "Port=" +  nPort  + ";" + ;
      "Stmt=;" + ;
      "User=" + cUser + ";" + ;
      "Password=" + cPassword + ";" + ;
      "Collation=utf8_general_ci;" + ;
      "AUTO_RECONNECT=1;" + ;
      "COMPRESSED_PROTO=1;" + ;
      "PAD_SPACE=1"
   cnConnection:CursorLocation    := 3
   cnConnection:CommandTimeOut    := 600 // seconds
   cnConnection:ConnectionTimeOut := 600 // seconds

RETURN cnConnection


Constante   Valor   Descrição
adStateClosed   0   Indica que o objeto está fechado.
adStateOpen   1   Indica que o objeto está aberto.
adStateConnecting   2   Indica que o objeto está se conectando.
adStateExecuting   4   Indica que o objeto está executando um comando.
adStateFetching   8   Indica que as linhas do objeto estão sendo recuperadas.
HARBOUR 3.2, HWGUI 2.23 B3, SEFAZCLASS, PDFClass, ADO + MariaDB/MySQL, RMChart
Fernando queiroz
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 737
Data de registro: 12 Nov 2014 23:41
Cidade/Estado: Porto Alegre/RS
Curtiu: 12 vezes
Mens.Curtidas: 58 vezes

SQL - Rollback

Mensagempor alxsts » 21 Fev 2021 17:39

Olá!
asimoes escreveu:Poderia mostrar o código da função ExecSQL ?
Essa forma só vendo como funciona a função ExecSQL( "BEGIN TRANSACTION;" )

O exemplo que postei acima é genérico e ExecSQL foi apenas uma referência a uma função que deve ser escrita pelo programador, de acordo com o método de acesso que ele utiliza (ADO, ODBC, SQLRDD...)
asimoes escreveu:BeginTrans(), CommitTrans() e RollBackTrans() são métodos do objeto ADODB.Connection, CommitTrans() e RollBackTrans() são métodos do objeto ADODB.Connection

Verdade. Mas antes de serem estes métodos do ADO, são comandos SQL, entendidos pelo SGBDR. ADO apenas encapsula isto em seus métodos. Quando solicitado, ADO executa o comando correspondente no SGBDR. Portanto, nada impede que, ao invés de consumir o método BeginTrans(), envie-se o correspondente comando ao SGBDR. No caso do MariaDB, pode ser "BEGIN" ou "START TRANSACTION". "COMMIT" e "ROLLBACK" são iguais aos demais bancos.
cnn.Execute "BEGIN",0, adExecuteNoRecords
cnn.Execute "ROLLBACK",0, adExecuteNoRecords
cnn.Execute "COMMIT",0, adExecuteNoRecords

Se o comando não se destinar a retornar resultados (por exemplo, uma consulta SQL UPDATE), o provedor não retornará nada enquanto a opção adExecuteNoRecords for especificada; caso contrário, execute retorna um conjunto de registros fechado. Algumas linguagens de aplicativo permitem ignorar esse valor de retorno se nenhum conjunto de registros for desejado.
Fonte: https://docs.microsoft.com/pt-br/sql/ado/reference/ado-api/execute-method-ado-command?view=sql-server-ver15

A função ExecSQL() deve executar comandos SQL. Os comandos SQL poder ser divididos, a grosso modo, em duas categorias:
os que retornam dados (um record set) e os que não fazem isto. Este fato deve ser considerado na construção de uma função tipo ExecSQL(). Tem programador que cria duas funções, uma para cada situação. Outros escrevem apenas uma, controlando a situação através de parâmetros recebidos. Assim podemos ter: ExecSQLQuery( oConn, cQuery ) ou ExecSQLNonQuery( oConn, cQuery ) ou ExecSQL( oConn, cQuery, lNonQuery ). E tem aqueles que usam ADO e não escrevem uma função - usam o método execute do objeto coneXão ou open do objeto recordset.

No tópico escrevi a função abaixo usando open do objeto recordset:
STATIC FUNCTION ExecuteSql( cSql )

   LOCAL oRs As Object
   LOCAL oErr As Object

   Try
      oRs := win_OleCreateObject("ADODB.RecordSet")

      With Object oRs
         :activeConnection := oCn:connectionString

         :cursorLocation := adUseClient
         :cursorType := adOpenDynamic

         :lockType := adLockOptimistic

         //:maxRecords := 100000
         :cacheSize := 100
         :source := cSql

         :open()
      End With

      If ! oRs:eof()
         oRs:moveFirst()
      Endif
     
   Catch oErr
      Throw( oErr )
   Finally
      IF oRs:state() = adStateOpen
         oRs:close()
      ENDIF
   End

   RETURN oRs

Fernando queiroz escreveu:Bom eu não faço o COMMIT e todas as transações são gravadas. ( sera que so funciona automatico no MARIADB ?? )

Os SGBDR tem como padrão o autocommit. No MariaDB, para desativar este padrão, pode-se executar o comando:
SET AUTOCOMMIT=0;  -- desativa 
SET AUTOCOMMIT=1; -- ativa autocommit

Quando autocommit está ativo, o commit é feito após a execução de cada comando.
Não me lembro onde li isto:
Quando se inicia uma transação (BEGIN ou SET TRANSACTION), internamente o SGBDR emite um SET AUTOCOMMIT=0;, desativando
o commit automático. Se aparecer um comando ROLL BACK ele despreza tudo e volta o estado anterior do auto commit. Se aparecer um
COMMIT, ele grava tudo e volta o estado anterior do auto commit.


Se der tempo, depois posto um exemplo.
[]´s
Alexandre Santos (AlxSts)
alxsts
Colaborador

Colaborador
 
Mensagens: 2943
Data de registro: 12 Ago 2008 15:50
Cidade/Estado: São Paulo-SP-Brasil
Curtiu: 21 vezes
Mens.Curtidas: 248 vezes

SQL - Rollback

Mensagempor asimoes » 21 Fev 2021 18:08

Não consegui funcionar no Maria DB dessa forma, não desfez o update que eu fiz na tabela

cnn.Execute "BEGIN",0, adExecuteNoRecords
cnn.Execute "ROLLBACK",0, adExecuteNoRecords
cnn.Execute "COMMIT",0, adExecuteNoRecords

Meu método para execução:
oConexao:ExecTrans( "BEGIN" )

oConexao:ExecTrans( "ROLLBACK" )

METHOD ExecTrans( cTransaction )
LOCAL oErro AS OBJECT, cErro AS STRING

   BEGIN SEQUENCE WITH {| oErro | oErro:cargo := {  oClPF:ListaFuncoes(2, oErro) }, Break( oErro ) }
      ::oConexao:Execute( cTransaction, 0, adExecuteNoRecords )
   RECOVER USING oErro
        cErro   := oErro:cargo[1]
   END

RETURN Nil
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes




Retornar para SQL

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 7 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro