2012-02-09 20 views
14

Tengo una aplicación C# que está insertando datos en la tabla de SQL Server (2008) utilizando el procedimiento almacenado. Estoy usando multi-threading para hacer esto. El procedimiento almacenado se llama desde dentro del hilo. Ahora mi procedimiento almacenado está usando "tablock" mientras inserto datos. Al ejecutar este código recibo el siguiente error: "Transaction (Process ID) se estancó en los recursos de bloqueo con otro proceso y se ha elegido como la víctima de interbloqueo. Vuelva a ejecutar la transacción".La transacción (ID de proceso) se bloqueó en los recursos de bloqueo con otro proceso y se ha elegido como la víctima de interbloqueo. Vuelva a ejecutar la transacción

¿Alguien puede ayudarme con alguna solución a esto?

+2

punto muerto en SQL Server, tendrá que añadir en su pregunta el código de procedimiento almacenado, así como la parte correspondiente de su esquema de base de datos. – ken2k

Respuesta

12

Esto ocurre cuando dos procesos de servidor Sql están accediendo a los mismos recursos, pero en un orden diferente. Por lo tanto, terminan esperando el otro proceso, que es un punto muerto.

Hay un número de maneras de prevenirlo, incluyendo:

  • Evitar tomar bloqueos innecesarios. Revise el nivel de aislamiento de transacción requerido para la consulta, use with (nolock) sugerencia de bloqueo para las consultas donde corresponda.
  • Asegúrese de que al tomar bloqueos toma bloqueos en objetos en el mismo orden en cada consulta.

E.g. si Proc1 bloquea table1 y luego table2, pero Proc2 bloquea table2 y luego table1, puede surgir el problema. Puede reescribir cualquier proc para tomar bloqueos en el mismo orden para evitar este problema.

2

Puede encapsular su consulta en un bloque intento de captura, y los números de error de captura (relativa a bloqueos)

  1. 1204
  2. 1205
  3. 1222

Entonces puede automatizar reintentos , hasta cierto número ... Entonces harías algo como lo siguiente;

  DECLARE @RetryNo Int = 1 
    ,@RetryMaxNo Int = 5; 
    WHILE @RetryNo < @RetryMaxNo 
     BEGIN 
     BEGIN TRY 

     -- put your query that generates locks here.... 

      SELECT @RetryNo = @RetryMaxNo; 
     END TRY 
     BEGIN CATCH 
      IF ERROR_NUMBER() IN (1204, 1205, 1222) 
       BEGIN 
        SET @RetryNo += 1; 
        -- it will wait for 10 seconds to do another attempt 
        WAITFOR DELAY '00:00:10'; 
       END 
      ELSE 
       THROW; 
     END CATCH 
     END 

También puede utilizar sugerencias de tabla como UPDLOCK.

+0

¿Por qué usas 'SELECT @RetryNo = @RetryMaxNo;' en lugar de 'BREAK;'? – Storm

+0

Porque en ese momento no queremos que falle, queremos reiterar el proceso y darle una cantidad máxima de intentos, antes de lanzar la excepción (si está relacionado con el tiempo de espera). – Mez

+0

¿Por qué 'BREAK' lo haría fallar? No lanzará una excepción porque ya ha pasado un código que podría hacer que falle, por lo que el 'BREAK' simplemente cortocircuitaría el ciclo. – Storm

0

se puede utilizar desde Proteger objeto

 static object _lock = new object(); 
    public static void _main() 
    { 
      lock (_lock) 
      { 
       _bulkcopy(myData); 
      } 
    } 
    public static void _bulkcopy(DataTable dt) 
    { 
     try 
     { 
      using (var connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("DBConnection"))) 
      { 
       connection.Open(); 
       SqlTransaction transaction = connection.BeginTransaction(); 

       using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction)) 
       { 
        bulkCopy.BatchSize = 100; 
        bulkCopy.DestinationTableName = "dbo.MyTable"; 
        try 
        { 
         bulkCopy.WriteToServer(dt); 
        } 
        catch (Exception) 
        { 
         transaction.Rollback(); 
         connection.Close(); 
        } 
       } 

       transaction.Commit(); 
      } 




     } 
     catch { } 
    } 
Cuestiones relacionadas