PDA

Ver la Versión Completa : Controlar Commit y Rollback


lucasarts_18
06-09-2006, 04:33:35
Hola compañeros del club:

Estoy realizando mantenciones a un sistema hecho en Delphi 4 y SQL Server 2000, y necesito cambiar algo de caracter importantísimo.

En primer lugar las transacciones están aisladas, ¿que quiero decir con esto?, pues que cada procedimiento almacenado de la base de datos contiene commit y rollback, siendo esto último no un problema para los mantenedores simples, por ejemplos productos, clientes, bodegas, etc...
Mi problema radica es que los modulos de ventas por ejemplo el de factura, al momento de grabar llama a varios SP (Ingresa Factura, Detalle Factura, Cta Corriente del cliente, Actualiza Stock, Etc....) lo cual al momento de producirse un fallo en el segundo u tercero.... SP me deja incosistencias en la BD ya que se produce un commit en cada procedimiento.
Sin lugar a dudas en estos casos lo mejor es controlarlo desde el programa todo lo referente a los commit y rollback, pero aquí yace mi gran duda...
Creo que con el código se entenderá un poco mejor:


if combo_vendedor.text ='' then
begin
MessageDlg('Ingrese el Código Vendedor', mtWarning, [mbOk],0);
combo_vendedor.Setfocus;
exit;
end;

if (edt_totalguia.Text ='') then
begin
MessageDlg('Debe Calcular el Valor Total de la Factura',mtWarning,[mbOk],0);
btn_Calculo.SetFocus;
exit;
end;

if Ingresar then
begin
Msg :='¿Desea Grabar el Ingreso de la Guía?';
if MessageDlg(Msg, mtConfirmation,[mbyes, mbNo],0) = mrYes then
begin
if (opcion_pago.ItemIndex in [0]) then
begin
Msg :='Favor, confirmar la opción de Pago con el CLIENTE'+ #13 + '< CONTADO >'+ #13 +'Si está correcto oprima [Ok], de lo contrario presione [Cancel]';
if MessageDlg(Msg, mtConfirmation,[mbOK, mbCancel],0) = mrCancel then
Exit;
end
else
begin
Msg :='Favor, confirmar la opción de Pago con el CLIENTE '+ #13 + '< CRÉDITO >'+ #13 +'Si está correcto oprima [Ok], de lo contrario presione [Cancel]';
if MessageDlg(Msg, mtConfirmation,[mbOK, mbCancel],0) = mrCancel then
Exit;
end;
IngresarGuia;
IngresarCorrelativo;
lv_i := 1;
while (lv_i <= grd_Detalle.RowCount -1) do
begin
IngresarDetalleGuia;
ActualizarStockProducto;
lv_i :=lv_i+1;
end;
MessageDlg('Guía de Despacho Ingresada Exitosamente.'+#13+'Ahora Deberá Imprimir.',mtInformation,[mbOk],0);
btn_buscarguia.Enabled := False;
btn_Nuevo.Enabled := False;
btn_Imprimir.Enabled := True;
btn_Grabar.Enabled := False;
btn_calculo.Enabled := False;
btn_Salir.Enabled := False;
PrecioNormal := 0;
PrecioOferta := 0;

end;
end;
end;



Supongamos IngresarGuia, IngresarCorrelativo son procedimientos delphi que a la vez llaman a procedimientos de SQL Server que contiene commit, mi idea es quitar los commit y en caso de error capturar el código error devuelto por la BD y este asignarlo a una variable pública del formulario para controlar el error, pero no se me ocurre muy bien como implementarlo, según ustedes ¿qué opción me recomendarían ?

Esperando que toda esta parafernalía se entienda :p

Hasta Luego -

kalimero
06-09-2006, 09:59:24
try
if not(conexion.InTransaction) then conexion.BeginTrans;
ingresarguia;
ingresarcorrelativo;
conexion.commit; //todo ha ido bien y confirmamos
except
//Capturamos la excepcion y hacemos lo que queramos
//Deshacemos la transaccion
conexion.Rollback;
end;

jachguate
06-09-2006, 15:54:30
Veo un defecto en el código de kalimero y es que se "traga" la excepción, por lo que aún cuando se ha realizado correctamente el rollback, pueden haber fallos posteriores debido a esto:

yo lo dejaría como:


Conexion.StartTransaction;
try
HacerTodoLoQueSeQuiera;
Conexion.Commit;
except
Conexion.Rollback;
raise; //esta línea eleva nuevamente la excepción original después del rollback
end;

Hasta luego.

;)

kalimero
06-09-2006, 17:27:46
Efectivamente Jachguate. No lo he dicho porque doy por supuesto que el interesado ya tenia claro este tema. Me he centrado en el objetivo de la pregunta era saber donde se ponen la llamadas a "begintrans" y "commit".
De todas formas el codigo correcto es el que tu has apuntado.

Saludos

jachguate
06-09-2006, 18:13:21
No lo he dicho porque doy por supuesto que el interesado ya tenia claro este tema.
Pero luego hay cada pelao que solo copia y pega... :cool:

lucasarts_18
07-09-2006, 05:47:32
yo lo dejaría como:


Código Delphi [-] (http://www.clubdelphi.com/foros/#)
Conexion.StartTransaction;
try
HacerTodoLoQueSeQuiera;
Conexion.Commit;
except
Conexion.Rollback;
raise; //esta línea eleva nuevamente la excepción original después del rollback
end;




Hasta luego.

;)

No entiendo del todo lo que te refieres con HacerTodoLoQueSeQuiera;
¿Realmente es poner todos los procedimientos delphi que tengo mas arriba en uno solo?

Con referente a tu último comentario, creo que no esta acorde a un forista que tiene más de 600 mensajes y que es motivo claro de un hecho de aprender y no salir del apuro...:mad:

Hasta Luego y gracias...:cool:

jachguate
07-09-2006, 16:53:40
No entiendo del todo lo que te refieres con HacerTodoLoQueSeQuiera;
¿Realmente es poner todos los procedimientos delphi que tengo mas arriba en uno solo?

No me refería a poner todo en uno solo, en realidad HacerTodoLoQueSeQuiera es eso... podes llamar a procedimientos, funciones, etc. Tantos como querras. ;)

Con referente a tu último comentario, creo que no esta acorde a un forista que tiene más de 600 mensajes y que es motivo claro de un hecho de aprender y no salir del apuro...:mad:

Hasta Luego y gracias...:cool:
Lamento no haber sido explicito y dar pie al malentendido, pero en realidad no me refería a vos. Te explico: Yo soy de los que creen que toda respuesta dada en estos foros se está dando en realidad a la comunidad, pues hay y habrán otros que un día se toparán con este tema dentro de una búsqueda... y dentro de esos, seguramente habrá algun pelao de esos que solo copian y pegan. Creeme que después de reponder, me quedé pensando también que esos pelaos, seguramente no llegarán a leer mi mensaje.. :D

Saludos.

;)

lucasarts_18
08-09-2006, 02:28:41
Lamento no haber sido explicito y dar pie al malentendido, pero en realidad no me refería a vos. Te explico: Yo soy de los que creen que toda respuesta dada en estos foros se está dando en realidad a la comunidad, pues hay y habrán otros que un día se toparán con este tema dentro de una búsqueda... y dentro de esos, seguramente habrá algun pelao de esos que solo copian y pegan. Creeme que después de reponder, me quedé pensando también que esos pelaos, seguramente no llegarán a leer mi mensaje.. :D

;)

Gracias por la aclaración, y gracias a ambos por resolver mi duda...

Hasta Luego - :)

cacu
08-11-2010, 00:12:41
Este problema podria tratarse con procedimientos anidados.
por otro lado puedes captutar el error en el mismo procedimiento
if @@erro<> o goto un_error:

un_error:
rolback
return(1);

aqui ya con la devolucion 1 puedes gestionar este erro

tarde la respuesta. jajaj y ademas no se si hubiese servido en el contextp de esta necesidad

jachguate
08-11-2010, 22:57:41
por otro lado puedes captutar el error en el mismo procedimiento
if @@erro<> o goto un_error:

un_error:
rolback
return(1);

aqui ya con la devolucion 1 puedes gestionar este erro



Francamente nunca he sido de la idea de hacer un rollback dentro de un procedimiento dentro de la propia base de datos.. no solo no es soportado por todos los motores, sino deja poca oportunidad para la re-utilización de código, ya que es indefinido (o al menos varía de motor a motor) cuál será el comportamiento con posibles próximas operaciones que uno podría suponer deben ir en el contexto de la misma transacción. En mi opinión, el control de las transacciones debe ser siempre explícito y desde fuera de los procedimientos y funciones almacenados.

Mis 2 centavos.