none
Transacciones restricciones tablas y registros RRS feed

  • Pregunta

  • Hola

    Llevo horas leyendo y probando y aun no he sido capaz de resolver mi problema... Lo expongo a ver:

    Estoy unsando transacciones para inserts, update y delete con NET de esta manera (la estandar):

    SqlConnection con = new SqlConnection("Connection String");
    SqlTransaction tr = con.BeginTransaction();
    SqlCommand cmd = new SqlCommand("Update Account set Balance=500 where AccountId=52", con, tr);
    try
    {
    cmd.ExecuteNonQuery();
    tr.Commit();
    }
    catch (Exception exc)
    {
    tr.Rollback();
    }
    finally
    {
    con.Close();
    }

    EL problema es que MIENTRAS se ejecuta la transaccion me deja TODA la tabla bloqueada...esto no tiene ningún sentido. Lo que pretendo conseguir es:

    - Cuando es insert : POder hacer otros inserts (por que no?), updates y deletes PERO q no se vean los registros insertados al hacer SELECT hasta que no hago el commit de la transacción

    - Cuando es UPDATE: Poder hacer inserts , updates MENOS el que estoy trabajando y deletes PERO q no se vean lo cambios de mi UPDATE hasta que no hago el commit de la transacción

    - Cuando hago delete: Poder hacer inserts, updates y deletes MENOS del que estoy borrando PERO q se vea el registro que voy ha borrar (pq. aun no he hecho el commit)

     

    Para esto me he leído esto:

    http://msdn.microsoft.com/es-es/library/ms173763.aspx

    http://technet.microsoft.com/es-es/library/ms187373.aspx

     

    En teoría para el Insert (aun estoy en el primero ya véis) he probado:

    connection.BeginTransaction(System.Data.IsolationLevel.Serializable, "SampleTransaction")

    y luego al recuperar Select * from [Aules] WITH (nolock) pero esto me muestar los que aun no están en commit

     

    A ver si alguien me dice que combinaciones de IsolationLevel y de restricción (es decir with) se ha de usar en cada caso

    Gracias

     

     


    GRacias

    • Editado chascos69 martes, 29 de noviembre de 2011 12:18
    • Cambiado Enrique M. Montejo sábado, 10 de diciembre de 2011 16:59 acceso a datos (De:Lenguaje VB.NET)
    martes, 29 de noviembre de 2011 12:17

Todas las respuestas

  • me deja TODA la tabla bloqueada...esto no tiene ningún sentido

    pero la transaccion deberia durar apenas unos segundos, que bloquee los registros en que afecta ?

     

    ademas porque no usas el TransactionScope

    es mucho mas practico de programar, como muestran los ejemplos del link, solo defines un bloque de codigo que englobe la transaccion

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    martes, 29 de noviembre de 2011 12:29
  • Si es una transaccion que dura 5 min (por ejemplo para insertar 1000 registros) si que afecta pq. otros usuarios que quieran trabajar con esa tabla (por ejemplo clientes) tendrán q esperar los 5 min q tarda la transacción... seguro q esto se puede evitar indicando que solo bloquee el registro con el q trabaja la transacción... pero como?

    Puedo usar el TransactionScope... no se en que se diferencian...??? pero intuyo que el problema lo tendré igual


    GRacias
    martes, 29 de noviembre de 2011 12:33
  • una transaccion que dura 5 min (por ejemplo para insertar 1000 registros) si que afecta pq. otros usuarios que quieran trabajar con esa tabla

    pero los procesos que duran tanto (y afectan la operatoria) deberian realizarse en un momento en que las personas no trabajan

    para eso existen los procesos que se realizan al final del dia labora, miles de aplicacioens realizan procesos complejos pero no lo hacen durante el dia laboral porque es sabido que esto afectara el rendimiento del trabajo y la respuesta

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    martes, 29 de noviembre de 2011 12:46
  • Hola:
    Si una transaccion dura 5 minutos es que hay algo que funciona muy mal.
    Insertar 1000 registros no deberia de tardar mas de 2-3 segundos.

    Un saludo desde Bilbo
    Carlos

    martes, 29 de noviembre de 2011 12:49
  • ....

    "pero los procesos que duran tanto (y afectan la operatoria) deberian realizarse en un momento en que las personas no trabajan"... a veces no se puede. Por ejemplo emitir una factura con sus detalles.. el cliente lo queire tener ese día... puede que si tiene mucho detalle tarde 5 min y no le puedes decir "no espera a la noche pq. como es un proceso q bloquea la tabla lo he de realizar por la noche". El cliente puede esperar 5 min pero no esperará 24 h

    "Si una transaccion dura 5 minutos es que hay algo que funciona muy mal. Insertar 1000 registros no deberia de tardar mas de 2-3 segundos."... era solo un ejemplo


    GRacias
    martes, 29 de noviembre de 2011 13:06
  • pero entocnes coincido con Carlos

    generar una factura no puede duran 5min es una barbaridad, ahora si esto actualzia stock, se comunca con otros sistemas, envia alerta, etc eso es lo que decia deberia realizarse como una tarea separada

    pero solo gneerar unso registros 5 min, es de locos

    has verifixado si los indices de las tablas o la db responde de forma correcta, porque en ese caso si algo esta mal

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    martes, 29 de noviembre de 2011 13:16
  • insisto.. es solo un ejemplo

    Coger el ejemplo de generar factura y detalle si queréis

    Centremosnos... No hay manera de a la hora de hacer una transacción que no te bloquee la tabla entera? Es decir, que otro user pueda hacer una select de esa tabla mientras se ejecuta la transacción


    GRacias
    martes, 29 de noviembre de 2011 14:06
  • select de esa tabla mientras se ejecuta la transacción

    las transacciones no deberian bloquear la tabla, menos aun para realizar un select

     

    vuelvo a recomendar prueba el TransactionScope


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    martes, 29 de noviembre de 2011 16:34
  • Ok ahora me reviso el método de TRansactionScope... que diferencia tiene con el TRansaction normal?

    Si suciera lo mismo ya lo indicaré

     

    Opino igual.. la transacción no debería bloquear la tabla pero lo hace. Ejecutar esto en una sql en el sql server para comprobar lo q digo:

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    GO
    BEGIN TRANSACTION;
    GO
    SELECT * FROM Tabla1
    WAITFOR DELAY '00:00:15' ---espero 15 seg
    GO
    COMMIT TRANSACTION;
    GO

    Y luego intentar hacer una select normal... no la hace
    SELECT * FROM Tabla1


    GRacias
    miércoles, 30 de noviembre de 2011 8:58
  • Hola:
    He realizado la siguiente prueba.
    Creo una tabla.
    CREATE TABLE [AA] (
     [ID] [int] NOT NULL ,
     CONSTRAINT [PK_AA] PRIMARY KEY  CLUSTERED
     (
      [ID]
     )  ON [PRIMARY]
    ) ON [PRIMARY]

    En un Form con 1 Button, copia y pega el siguiente codigo

    Imports System.Data.SqlClient
    Public Class Form1
        Dim msCadenaSQL As String = "Data Source=.\SQLEXPRESS;Initial Catalog=TUBASEDEDATOS;Integrated Security=True"

        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim lsQuery As String
            Dim lStopWatch As New Stopwatch
            lStopWatch.Start()
            Dim Duracion As TimeSpan
            Try
                Using loConexion As New SqlConnection(msCadenaSQL)
                    'Iniciamos una transaccion
                    Using MiTransaccion As New Transactions.TransactionScope
                        loConexion.Open()
                        Using loComando As New SqlCommand
                            For liCiclo As Int32 = 1 To 100000
                                lsQuery = "Insert Into AA (ID) Values (" & CStr(liCiclo) & ")"
                                loComando.Connection = loConexion
                                loComando.CommandText = lsQuery
                                loComando.ExecuteNonQuery()
                            Next
                        End Using
                        MiTransaccion.Complete()
                    End Using
                End Using
            Catch Exp As SqlException
                Me.Cursor = Cursors.Default
                MessageBox.Show(Exp.Message, "Button1_Click", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Catch Exp As Exception
                Me.Cursor = Cursors.Default
                MessageBox.Show(Exp.Message, "Button1_Click", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End Try
            lStopWatch.Stop()
            Duracion = lStopWatch.Elapsed
            Dim lsDiferencia As String = "'" & String.Format("{0:00}:{1:00}:{2:00}", Duracion.Hours, Duracion.Minutes, Duracion.Seconds) & "'"
            MessageBox.Show(lsDiferencia)
        End Sub
    End Class

    En el mensaje que saca dice que para insertar 100.000 registros se necesita un tiempo de 11 segundos.
    Para insertar una factura y sus detalles correspondientes se puede necesitar del orden de milisegundos,
    no creo que sea mucho bloquear.

    Un saludo desde Bilbo
    Carlos

    miércoles, 30 de noviembre de 2011 10:10
  • Insisto.. es solo un ejemplo

    Lo que no tiene mucho sentido es que por hacer una transacción en una tabla te deje esa tabla bloqueada incluso para un simple select... como si son 10 segundos... otro user q quiera hacer una select en esa tabla tiene q esperarse 10 seg a q la transacción acabe? Y si son 3 transacciones (una por clientes, otra por facturas, otra por yo q se... estudios de markeing) y cada una tarda 10 seg q tiene q esperarse 30 seg para hace run select? No lo veo lógico....


    GRacias
    miércoles, 30 de noviembre de 2011 11:59
  • como haz validado el bloqueo ?

     

    no probaste definiendo el parametro

    IsolationLevel (Enumeración)

     

    del metodo

    SqlConnection.BeginTransaction Method

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    miércoles, 30 de noviembre de 2011 12:26
  • objTransaction = connection.BeginTransaction(System.Data.IsolationLevel.RepeatableRead, _
                                                          "SampleTransaction")

    Las he probado todas....

    'Defecto: READ COMMITTED según http://msdn.microsoft.com/es-es/library/ms173763.aspx
             'Chaos no funciona
             'ReadCommitted, ReadUncommitted, RepeatableRead, Serializable, SnapShot  y Unspecified no deja hacer select en tabla
             'Fuente: http://msdn.microsoft.com/es-es/library/ms173763.aspx
             'Mientras se ejecuta la transacción solo me funcionó estos:
             'select * from [Aules] WITH (READPAST)  --No lee las filas bloqueadas por otras transacciones.  No interesa
             'select * from [Aules] WITH (READUNCOMMITTED) --Devuelve las filas q aun no se ha hecho commit

    Estos no funcionaron:

             '--select * from [Aules]

             '--select * from [Aules] WITH (PAGLOCK)
             '--select * from [Aules] WITH (READCOMMITTED)
             '--select * from [Aules] WITH (REPEATABLEREAD)
             '--select * from [Aules] WITH (ROWLOCK)
             '--select * from [Aules] WITH (SERIALIZABLE)
             '--select * from [Aules] WITH (TABLOCK)
             '--select * from [Aules] WITH (TABLOCKX)
             '--select * from [Aules] WITH (UPDLOCK)
             '--select * from [Aules] WITH (XLOCK)

    Además por lo q he leído el ISOLATION LEVEL es solo para definir el nivel de acceso PARA OTRAS TRANSACCIONES... es decir, yo puedo estar ejecutando una transacción y en paralelo ejecutar otra q trabje con la misma tabla y actua... de hecho estoy seguro pq. lo he probado PERO sin embargo me voy al sql server y hago una SELECT y no responde hasta q acaba la transacción


    GRacias
    miércoles, 30 de noviembre de 2011 12:42