No use una transacción para el procedimiento almacenado
18
Tengo un procedimiento almacenado que ejecuta algunos comandos. No quiero que estos comandos se envuelvan en la transacción del procedimiento almacenado. Si el cuarto comando falla, quiero que el primero, el segundo y el tercero se queden y no retrocedan.
¿Es posible escribir el procedimiento almacenado de tal manera que no todo se ejecute como una gran transacción?
Todas las transacciones no se ejecutarán en una sola transacción. Echale un vistazo a éste ejemplo:
use TestDB;
go
ifexists(select1from sys.tables where object_id = object_id('dbo.TestTranTable1'))droptable dbo.TestTranTable1;createtable dbo.TestTranTable1
(
id int identity(1,1)notnull,
some_int int notnulldefault1);
go
insertinto dbo.TestTranTable1
defaultvalues;
go 4select*from dbo.TestTranTable1;ifexists(select1from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))begindropproc dbo.ChangeValues;end
go
createproc dbo.ChangeValues
asupdate dbo.TestTranTable1
set some_int =11where id =1;update dbo.TestTranTable1
set some_int =12where id =2;update dbo.TestTranTable1
set some_int =13where id =3;-- this will error out (arithmetic overflow)update dbo.TestTranTable1
set some_int =2147483648where id =4;
go
exec dbo.ChangeValues;select*from dbo.TestTranTable1;
Aquí está la salida:
Al crear una sesión de eventos extendidos para monitorear el sql_transactionevento, aquí está el resultado de la ejecución dbo.ChangeValues:
Como puede ver en esta captura de pantalla anterior, hay transacciones separadas para cada una de las cuatro declaraciones. Los primeros 3 se comprometen y el último retrocede debido al error.
Creo que puede haber cierta confusión aquí sobre un lote frente a una transacción .
Una transacción es una declaración o conjunto de declaraciones que tendrán éxito o fallarán como una unidad. Todas las instrucciones DDL están en transacciones mismas (es decir, si actualiza 100 filas pero la fila 98 arroja un error, ninguna de las filas se actualiza). También puede ajustar una serie de declaraciones en una transacción usando BEGIN TRANSACTIONy luego COMMITo ROLLBACK.
Un lote es una serie de declaraciones que se ejecutan juntas. Un procedimiento almacenado es un ejemplo de un lote. En un procedimiento almacenado, si una declaración falla y hay un error de captura (normalmente TRY/CATCHbloques), las siguientes declaraciones no se ejecutarán.
Sospecho que su problema es que el lote se cancela cuando se produce un error porque el proceso almacenado en sí mismo o un ámbito externo (como la aplicación o el proceso almacenado que llama a este procedimiento) tiene un error de captura. Si ese es el caso, es más difícil de resolver ya que debe ajustar la forma en que maneja los errores en cualquier ámbito que los esté atrapando.
No encontré ningún artículo que diga: "Un procedimiento de tienda es un ejemplo de un lote". Creo que el procedimiento almacenado es muy similar al lote pero no es un lote. La principal diferencia es: se garantiza que SP se compilará por adelantado y estará listo para su ejecución varias veces, a diferencia de los lotes. Las similitudes son: - Ambos ejecutan cada comando a la vez. - Si falla un comando, se confirman todos los comandos anteriores (a menos que se esté ejecutando en una transacción); si un comando falla, no se ejecutan todos los comandos siguientes.
Ashi
6
Todo en el servidor SQL está contenido en una transacción.
Así es como funcionan los procedimientos almacenados de forma predeterminada. El procedimiento almacenado no se ajusta dentro de una transacción automáticamente.
Si desea que el procedimiento almacenado se detenga cuando llegue al primer error, querrá poner algún inicio de sesión TRY / CATCH allí para regresar en caso de un problema con el comando 2, por ejemplo.
Quiero calificar esas transacciones individuales como el comportamiento predeterminado para los procedimientos almacenados, porque todas las declaraciones están envueltas en transacciones implícitas; sin embargo, nadie debe confiar en transacciones implícitas para controlar el destino de su código. Es una práctica mucho mejor controlar explícitamente la forma en que se manejan las transacciones en el código de producción.
separe cada una de las partes con un BEGIN TRAN y verifique si la transacción fue exitosa. si fue confirmarlo, de lo contrario, haga una reversión, ya que todos se están ejecutando desde el mismo nivel, podrá confirmar cada sección por separado sin tener que retroceder todo si falla.
¿Eso creará sub transacciones dentro de mi Procedimiento almacenado? Idealmente me gustaría evitar eso si es posible
Matthew Steeples
1
Si se llama al SP desde una transacción, las transacciones guardadas arriba son la respuesta. Si no se llama a sp, entonces @mrdenny es correcto. El servidor SQL no admite transacciones anidadas.
Para ser claros (y para los perezosos que no quieren hacer clic en los enlaces), en realidad no están comenzando otra transacción. También conocido como el título en la publicación de Paul: "Mito: las transacciones anidadas son reales". No son transacciones reales. COMMIT en una transacción anidada no hace nada excepto decrementar @@ TRANCOUNT. Es cierto que no obtendrá un error si anida BEGIN TRAN / COMMIT, pero eso es diferente de tener transiciones anidadas reales.
Todo en el servidor SQL está contenido en una transacción.
Cuando especifica explícitamente
begin transaction
yend transaction
luego se llama Transacción explícita . Cuando no lo hace, entonces es una transacción implícita .Para cambiar en qué modo estás, usarías
o
si lo anterior devuelve 2, está en modo de transacción implícita. Si devuelve 0, está en confirmación automática.
Una transacción es TODO o nada para mantener la base de datos en un estado coherente ... recuerde las propiedades de ACID.
- cree SP ahora - tenga en cuenta que los primeros 3 tendrán éxito y el cuarto fallará debido al truncamiento de la cadena ...
Consulte: ¿Es una mala práctica crear siempre una transacción?
fuente
Así es como funcionan los procedimientos almacenados de forma predeterminada. El procedimiento almacenado no se ajusta dentro de una transacción automáticamente.
Si desea que el procedimiento almacenado se detenga cuando llegue al primer error, querrá poner algún inicio de sesión TRY / CATCH allí para regresar en caso de un problema con el comando 2, por ejemplo.
fuente
Necesitará transacciones individuales para cada comando. También puede lograr esto con transacciones guardadas:
Ver
SAVE TRANSACTION (Transact-SQL)
en la documentación del producto.Quiero calificar esas transacciones individuales como el comportamiento predeterminado para los procedimientos almacenados, porque todas las declaraciones están envueltas en transacciones implícitas; sin embargo, nadie debe confiar en transacciones implícitas para controlar el destino de su código. Es una práctica mucho mejor controlar explícitamente la forma en que se manejan las transacciones en el código de producción.
fuente
separe cada una de las partes con un BEGIN TRAN y verifique si la transacción fue exitosa. si fue confirmarlo, de lo contrario, haga una reversión, ya que todos se están ejecutando desde el mismo nivel, podrá confirmar cada sección por separado sin tener que retroceder todo si falla.
Para obtener más información, puede consultar: http://msdn.microsoft.com/en-us/library/ms188929.aspx
fuente