none
Transactions não dão rollback RRS feed

  • Pergunta

  • Pessoal, estou com uma duvida, algo um tanto esquisito está acontecendo com um comando, ou eu que não estou sabendo gerenciar.

    O comando a seguir, contem duas instruções de inserção no BD, para grava um lançamento de conta e seu respectivo pagamento (supondo um exemplo que seria uma venda a vista).

    Como a conta (Lancamento) ainda não existe e a chave é um identity, obtivemos a chave para gravar na tabela referenciada atraves do scope_identity;

    Podem ocorrer erros em um dos comandos, e nesse caso, teria que desfazer o processo (não gravar nenhum dos dois) para manter a consistencia, por isso o uso de Transaction.

    ------------------------------------

    BEGIN TRANSACTION
    insert into Lancamentos (Numero, CodCliente, Tipo, Sequencia, datacriacao)
    values (
        'asdfghg11111111111111111111111111111', 27, 'r', 1, GETDATE()
    );
    insert into Pagamentos (seq, seqLancamento, SequenciaPagamento, Valor, DataCriacao)
    values (
        (select max(seq)+1 from fn_pagamento)  --seq
        , SCOPE_IDENTITY() --seqLancamento
        , 1, 50.00, GETDATE());
    if @@ERROR <> 0
       ROLLBACK
    else
        COMMIT
    ------------------------------------

    Provoquei um erro na primeira inserção, e parece que não deu certo. Está inserindo o Pagamento mesmo tendo dado erro na primeira instrução insert.

    Pode ser alguma coisa que estou fazendo errado? ou algo de configuração de BD?


    Julio C.

    sábado, 10 de maio de 2014 12:56

Respostas

  • Interessante

    Acho que a resolução é por aí mesmo, a questão então é controlar bem os erros..

    eu achei que havia uma forma mais "intuitiva" do BD mesmo controlar..


    Julio C.

    Julio,

    Eu tenho a mesma idéia do José de utilizar o TRY ... CATCH neste script T-SQL.

    A única mudança que eu faria é no bloco CATCH, como segue abaixo:

    BEGIN CATCH
    	if @@ERROR <> 0
    	 BEGIN
    		PRINT 'ERRO'
    		ROLLBACK
    	  END
    
    END CATCH
    

    O tratamento de erros é algo muito importante e que pode evitar ou gerar muitos problemas se não for bem estruturado.

    Acredito que você não deve encontrar formas mais intuitivas de tratamento de erros. Quase sempre às linguagens de programação, inclusive o T-SQL, seguem um processo semelhante à este. Se você encontrar algo mais simples, desconfie e realize diversos testes de acordo com sua utilização estimada.

    Para maiores informações sobre TRY ... CATCH em T-SQL veja:

    http://msdn.microsoft.com/pt-br/library/ms175976.aspx

    Se ajudou na sua solução, não esqueça de marcar como resposta !

    Abraços,

    Durval Ramos
    Microsoft Partner | MTA | MCSA - SQL Server 2012 | MCSE - Data Platform
    ----------------------------------
    Se foi resolvido clique "Marcar como resposta" e se foi útil "Votar como Útil"
    • Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
    segunda-feira, 12 de maio de 2014 19:23
    Moderador
  • Deleted
    • Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
    domingo, 11 de maio de 2014 23:21

Todas as Respostas

  • Deleted
    • Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
    domingo, 11 de maio de 2014 23:21
  • Humm entendi

    mas se eu identificar que estou usando a transação, para executar 2 comandos, não deveria ser atualizado tudo no final (comitado) somente se todos os comandos da transação fossem executados com sucesso?

    Isso é se der um problema no meio, o sql server segue adiante e comita assim mesmo?


    Julio C.

    segunda-feira, 12 de maio de 2014 14:19
  • Humm entendi

    mas se eu identificar que estou usando a transação, para executar 2 comandos, não deveria ser atualizado tudo no final (comitado) somente se todos os comandos da transação fossem executados com sucesso?

    Isso é se der um problema no meio, o sql server segue adiante e comita assim mesmo?


    Julio C.

    Julio,

    Provavelmente o COMMIT executou porque os dados que você esta utilizando atendem todas às condições para inclusão do registro (data type, CONSTRAINT, ...).

    Você poderia postar a estrutura dessas duas tabelas, indicando quais são seus campos IDENTITY para que possamos simular este problema ?


    Abraços,

    Durval Ramos
    Microsoft Partner | MTA | MCSA - SQL Server 2012 | MCSE - Data Platform
    ----------------------------------
    Se foi resolvido clique "Marcar como resposta" e se foi útil "Votar como Útil"
    segunda-feira, 12 de maio de 2014 15:03
    Moderador
  • Deleted
    segunda-feira, 12 de maio de 2014 17:42
  • Ola Durval

    é só um exemplinho que simplifiquei bastante,

    Mas essencialmente, a tabela Lancamentos tem um SeqLancamento que é identity,

    Após inserir na Lancamentos, ao inserir na Pagamentos, deve ser obtido esse seqLancamento gerado, com o scope_identity().

    No caso, o campo Numero é varchar(10), então eu provoquei um erro propositalmente na primeira inserção: o Numero não aceita string daquele tamanho.. nesse caso, gostaria que desse um erro e a transação não seguisse adiante.

    Mas ocorreu que não executou esta (deu erro) e seguiu adiante, ficando inconsistente. Na verdade, eu sei que não deveria deixar inserir na tabela Pagamentos, se tivesse a constraint de relacionamento criada.. não tem ela..

    Mas em diversos outros casos que eu tenho (bem mais complexos, que geram vários comandos), se houvesse algum comando executado antes dele dentro da mesma transaction, gostaria que voltasse tudo que foi executado na transação e não foi comitado, ... acho que seria essa a essencia de usar as Transactions.


    Valeu


    Julio C.

    segunda-feira, 12 de maio de 2014 18:08
  • drop table [dbo].[Lancamentos]
    drop table [dbo].[Pagamentos]
    CREATE TABLE [dbo].[Lancamentos](
    	[seqLancamento] [bigint] IDENTITY(1,1) NOT NULL,
    	[CodCliente] [int] NOT NULL,
    	[Numero] [varchar](10) NULL,
    	[Tipo] [varchar](1) NOT NULL,
    	[Sequencia] [int] NOT NULL,
    	[DataCriacao] [datetime] NULL,
    CONSTRAINT [PK_Lancamentos] PRIMARY KEY CLUSTERED
    (
    	[seqLancamento] ASC
    )
    )
    
    
    
    CREATE TABLE [dbo].[Pagamentos](
    	[seq] [bigint] NOT NULL,
    	[seqLancamento] [bigint] ,
    	[SequenciaPagamento] [int] NOT NULL,
    	[Valor] [money] NULL,
    	[DataCriacao] [datetime] NULL,
    CONSTRAINT [PK_Pagamentos] PRIMARY KEY CLUSTERED
    (
    	[seq] ASC
    )
    )
    
    
    
    BEGIN TRANSACTION
    insert into Lancamentos (Numero, CodCliente, Tipo, Sequencia, datacriacao)
    values (
        'asdfghg11111111111111111111111111111', 27, 'r', 1, GETDATE()
    );
    insert into Pagamentos (seq, seqLancamento, SequenciaPagamento, Valor, DataCriacao)
    values (
        (select max(seq)+1 from fn_pagamento)  --seq
        , SCOPE_IDENTITY() --seqLancamento
        , 1, 50.00, GETDATE());
    if @@ERROR <> 0
       ROLLBACK
    else
        COMMIT
        
        
        select * from Lancamentos
        select * from Pagamentos 


    Julio C.

    segunda-feira, 12 de maio de 2014 18:21
  • Interessante

    Acho que a resolução é por aí mesmo, a questão então é controlar bem os erros..

    eu achei que havia uma forma mais "intuitiva" do BD mesmo controlar..


    Julio C.

    segunda-feira, 12 de maio de 2014 18:23
  • Obs !!!

    só para constar, eu uso transactions atualmente, por meio do objeto SqlTransaction, do .Net, funciona bem (ele deve fazer tudo isso de forma transparente).

    Mas estou analisando alguns casos, em que vai ser mais interessante "fazer via SQL" mesmo (quero dizer, explorar mais o BD diretamente).

    Obrigado!!


    Julio C.

    segunda-feira, 12 de maio de 2014 18:26
  • Interessante

    Acho que a resolução é por aí mesmo, a questão então é controlar bem os erros..

    eu achei que havia uma forma mais "intuitiva" do BD mesmo controlar..


    Julio C.

    Julio,

    Eu tenho a mesma idéia do José de utilizar o TRY ... CATCH neste script T-SQL.

    A única mudança que eu faria é no bloco CATCH, como segue abaixo:

    BEGIN CATCH
    	if @@ERROR <> 0
    	 BEGIN
    		PRINT 'ERRO'
    		ROLLBACK
    	  END
    
    END CATCH
    

    O tratamento de erros é algo muito importante e que pode evitar ou gerar muitos problemas se não for bem estruturado.

    Acredito que você não deve encontrar formas mais intuitivas de tratamento de erros. Quase sempre às linguagens de programação, inclusive o T-SQL, seguem um processo semelhante à este. Se você encontrar algo mais simples, desconfie e realize diversos testes de acordo com sua utilização estimada.

    Para maiores informações sobre TRY ... CATCH em T-SQL veja:

    http://msdn.microsoft.com/pt-br/library/ms175976.aspx

    Se ajudou na sua solução, não esqueça de marcar como resposta !

    Abraços,

    Durval Ramos
    Microsoft Partner | MTA | MCSA - SQL Server 2012 | MCSE - Data Platform
    ----------------------------------
    Se foi resolvido clique "Marcar como resposta" e se foi útil "Votar como Útil"
    • Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
    segunda-feira, 12 de maio de 2014 19:23
    Moderador