none
insertar un registro pero antes validar su existencia RRS feed

  • Pregunta

  •  

    que tal ?, trabajo en visual studio 2003 (asp.net, c# + sql server 2000)  y estoy intentando armar una capa de acceso a datos para una aplicacion web, mi problema es es siguiente,

    cuando quiero insertar un registro en particular quiero verificar que exista y si no existe insertarlo, arme 2 metodos el primero llama a un sp y verifica si existe el segundo inserta el dato si es q no existe, pero en un ambiente multiusuario , puede ocurrir que entre metodo y metodo me inserte el dato otro usuario , para esto aplique una restriccion UNIQUE, mi pregunta es si existe algun metodo mejor q este para resolver este problema.

    muchas gracias.

     

    martes, 11 de septiembre de 2007 15:32

Todas las respuestas

  • Puedes utilizar locks en SQL Server:

     

    http://www.mssqlcity.com/Articles/Adm/SQL70Locks.htm

     

    Salu2

    martes, 11 de septiembre de 2007 15:51
  • Modos de bloqueo InnoDB

    InnoDB implementa un bloqueo a nivel de fila estándar, donde hay dos tipos de bloqueos:

    • Compartido (Shared) (S) le permite a una transacción leer una fila.

    • Exclusivo (Exclusive) (X) le permite a una transacción actualizar o eliminar una fila.

    Si una transacción A sostiene un bloqueo exclusivo (X) sobre una tupla t, entonces una solicitud de otra transacción Bt no puede ser atendida inmediatamente. En lugar de eso, la transacción B debe esperar a que la transacción A libere el bloqueo en la tupla t. para establecer un bloqueo de cualquier tipo sobre

    Si la transacción A sostiene un bloqueo compartido (S) sobre una tupla t, entonces

    • Una solicitud de otra transacción B para un bloqueo X sobre t no puede ser atendido inmediatamente.

    • Una solicitud de otra transacción B para un bloqueo S sobre t puede ser atendido inmediatamente. En consecuencia, tanto A como B sostendrán un bloqueo S sobre t.

    Adicionalmente, InnoDB soporta bloqueo de granularidad múltiple (multiple granularity locking), el cual permite que existan simultáneamente bloqueos en registros y bloqueos en tablas enteras. Para hacer práctico el nivel de bloqueo de granularidad múltiple, se emplean tipos adicionales de bloqueo, llamados bloqueos de intención (intention locks). Los bloqueos de intención son bloqueos de tabla en InnoDB. La idea detrás de los mismos es que una transacción indique qué tipo de bloqueo (compartido o exclusivo) requerirá más tarde sobre una fila de esa tabla. En InnoDB se utilizan dos tipos de bloqueos de intención (asumiendo que la transacción T ha solicitado un bloqueo del tipo indicado en la tabla R):

    • Intención compartida (Intention shared) (IS): La transacción T trata de establecer bloqueos S en tuplas individuales de la tabla T.

    • Intención exclusiva (Intention exclusive) (IX): La transacción T trata de establecer bloqueos X en las tuplas.

    Luego, el protocolo de bloqueo de intención es el siguiente:

    • Antes de que de una determinada transacción logre un bloqueo S en una determinada fila, primero debe conseguir establecer un bloqueo IS o superior en la tabla que contiene a la fila.

    • Antes de que de una determinada transacción logre un bloqueo X en una determinada fila, primero debe conseguir establecer un bloqueo IX en la tabla que contiene a la fila.

    Estas reglas pueden resumirse convenientemente por medio de una matriz de compatibilidad entre tipos de bloqueo:

      X IX S IS -
    X N N N N S
    IX N S N S S
    S N S S S S
    IS N S S S S
    - S S S S S

    Por lo tanto, los bloqueos de intención solamente bloquean solicitudes sobre tablas completas (Ej: LOCK TABLES ... WRITE). El propósito principal de IX y IS es mostrar que alguien está bloqueando una fila, o va a bloquear una fila en la tabla.

    jueves, 11 de octubre de 2007 19:41
  • Bloquear lecturas SELECT ... FOR UPDATE y SELECT ... LOCK IN SHARE MODE

    En ciertas circunstancias, no es conveniente una lectura consistente. Por ejemplo, se podría desear agregar una fila en la tabla hijo, y estar seguro de que dicha fila tiene una fila padre en la tabla padre. El siguiente ejemplo muestra cómo implementar integridad referencial en el código de la aplicación.

    Suponiendo que se utiliza una lectura consistente para leer la tabla padre y efectivamente puede verse el registro padre para la fila hijo que se agregará, ¿puede agregarse en forma segura la fila hijo dentro de la tabla hijo? No, porque puede haber ocurrido que entretanto otro usuario haya borrado el registro padre de la tabla padre, sin que se tenga conocimiento de ello.

    La solución es llevar a cabo el SELECT en un modo con bloqueo, utilizando LOCK IN SHARE MODE:

    SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

    Realizar una lectura en modo compartido (share mode) significa que se leen los últimos datos disponibles, y se establece un bloqueo en modo compartido en los registros que se leen. Un bloqueo en modo compartido evita que otros actualicen o eliminen la fila que se ha leido. Además, si los datos más actualizados pertenecen a una transacción todavía no confirmada de otra conexión, se espera hasta que la transacción se confirme. Luego de ver que la mencionada consulta devuelve el registro padre 'Jones', se puede agregar con seguridad el registro hijo en la tabla hijo y confirmar la transacción.

    Otro ejemplo: se tiene un campo contador, entero, en una tabla llamada child_codes que se emplea para asignar un identificador único a cada registro hijo agregado a la tabla hijo. Obviamente, utilizar una lectura consistente o una lectura en modo compartido para leer el valor actual del contador no es una buena idea, puesto que dos usuarios de la base de datos pueden ver el mismo valor del contador, y agregar registros hijos con el mismo identificador, lo cual generaría un error de clave duplicada.

    En este caso, LOCK IN SHARE MODE no es una buena solución porque si dos usuarios leen el contador al mismo tiempo, al menos uno terminará en un deadlock cuando intente actualizar el contador.

    En este caso, hay dos buenas formas de implementar la lectura e incremento del contador: (1), actualizar el contador en un incremento de 1 y sólo después leerlo, o (2) leer primero el contador estableciendo un bloqueo FOR UPDATE, e incrementándolo luego. La última puede ser implementada como sigue:

    SELECT counter_field FROM child_codes FOR UPDATE;
    UPDATE child_codes SET counter_field = counter_field + 1;

    Una sentencia SELECT ... FOR UPDATE lee el dato más actualizado disponible, estableciendo bloqueos exclusivos sobre cada fila leída. Es decir, el mismo bloqueo que haría UPDATE.

    Nótese que el anterior es un sencillo ejemplo de cómo funciona SELECT ... FOR UPDATE. En MySQL, la tarea específica para generar un identificador único en realidad puede realizarse utilizando un sólo acceso a la tabla:

    UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
    SELECT LAST_INSERT_ID();

    jueves, 11 de octubre de 2007 19:47