Usuário com melhor resposta
Transactions não dão rollback

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.
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 RamosMicrosoft 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
-
Deleted
- Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
Todas as Respostas
-
Deleted
- Marcado como Resposta Giovani Cr terça-feira, 13 de maio de 2014 20:17
-
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.
-
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 RamosMicrosoft Partner | MTA | MCSA - SQL Server 2012 | MCSE - Data Platform---------------------------------- Se foi resolvido clique "Marcar como resposta" e se foi útil "Votar como Útil" -
-
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.
-
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.
-
-
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.
-
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 RamosMicrosoft 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