Friday, August 25, 2006

finally {} no es un buen lugar para confirmar las transacciones

Acabo de arreglar un codigo que estaba mas o menos asi::

transaction = connection.BeginTransaction();
try {
try
{
//***.... algunas operaciones en la DB aqui...
} finally {
transaction.Commit();
}
}
catch {
transaction.RollBack();
}

Primero que nada, hay un bug ahi, si el codigo de enmedio nos diera una exception, este codigo generaria una nueva exception en la seccion del catch{} porque no podemos hacer rollback a una transaccion que ya se le hizo commit (el mensaje no sera asi de claro, pero eso es lo que quiere decir, la excepcion dice algo como que la operacion no puede ser completada debido al estado actual del objeto), y perderas la informacion de la excepcion original


Segundo, simplemente esta mal!, quita cualquier beneficio que tenias con la transaccion, es como decir:


//*** borrar algunos registros


//*** actualizar algunos registros


//*** alguna operacion que causo una excepcion


//*** finalmente, confirmar lo que halla hecho hasta ahorita


Dejando tus datos en un estado indeterminado (no sabes hasta donde llego tu codigo antes del error) porque confirmaste la operacion hasta donde los errores hallan ocurrido.


pista: siempre usa "using" para cualquier cosa relacionada con la base de datos (connecciones, commandos, transacciones, etc)

update: gracias a Kamikaze por encontrar un bug

4 comments:

Anonymous said...

Interesante blog. Programo bastante en c# y me gusta este tipo de blogs, llenos de trucos interesantes para aplicar día a día.

¡Ánimo!.

BlackTigerX said...

ahi estamos aportando un granito de arena; en ingles hay mucho material, y se que hay muchos desarrolladores hispanos que desafortunadamente (para su suerte) no mastican el lenguaje de Shakespeare (osea el ingles pues)

y pues espero poder contribuir un poco con este blog

KaMiKaZe said...

oye, pero creo que el bug en realidad está en el orden del try/catch.

¿qué el orden no es try/catch/finally, en lugar de try/finally/catch? (Creo que fue error del post, porque no creo que el compilador te permita un orden distinto.)

Finally se ejecuta siempre (se haya o no levantado una excepción) y si pones ahi el Commit pues no sirve de nada. En cualquier caso, tienes razón. El commit debería en dado caso hacia el final dentro del try, y en dado caso el rollback en el catch.

Mejor aún si especificas el tipo de exception, aunque no hagas nada con ella

// asumiendo SQL Data Provider
try {}
catch (SqlException) {}
catch (ApplicationException){}
// etc.
finally {}

BlackTigerX said...

ups, el codigo lo teclee aqui directamente, deberia tener otro block de try..catch afuera de ese try..finally

deja lo arreglo

gracias