Es posible, aunque engorroso, hacer esto. Como bortzmeyer says, es peligroso confiar en los valores de las secuencias que son contiguas, por lo que es mejor dejar las cosas como están si es posible.
Si no puede:
Cada acceso a la tabla que podría causar una fila para tener un cierto nombre (es decir, todos los INSERT
a la mesa, y si usted lo permite (aunque es una mala práctica) cada UPDATE
que podría cambiar el campo name
) debe hacerlo dentro de una transacción que bloquee primero todo. La opción más simple y menos eficiente es simplemente bloquear toda la tabla usando LOCK users IN EXCLUSIVE MODE
(agregar las últimas 3 palabras permite el acceso de lectura concurrente por otros procesos, lo cual es seguro).
Sin embargo, es un bloqueo muy grueso que ralentizará el rendimiento si hay muchas modificaciones simultáneas en users
; una mejor opción sería bloquear una única fila correspondiente en otra tabla que ya debe existir. Esta fila se puede bloquear con SELECT ... FOR UPDATE
. Esto tiene sentido solo cuando se trabaja con una tabla "secundaria" que tiene una dependencia FK en otra tabla "principal".
Por ejemplo, imagina por el momento que estamos tratando de crear de forma segura orders
para un customer
, y que estas órdenes de alguna manera tienen 'nombres' identificativos. (Lo sé, pobre ejemplo ...) orders
tiene una dependencia de FK en customers
. A continuación, para evitar que alguna vez la creación de dos órdenes con el mismo nombre para un cliente determinado, se puede hacer lo siguiente:
BEGIN;
-- Customer 'jbloggs' must exist for this to work.
SELECT 1 FROM customers
WHERE id = 'jbloggs'
FOR UPDATE
-- Provided every attempt to create an order performs the above step first,
-- at this point, we will have exclusive access to all orders for jbloggs.
SELECT 1 FROM orders
WHERE id = 'jbloggs'
AND order_name = 'foo'
-- Determine if the preceding query returned a row or not.
-- If it did not:
INSERT orders (id, name) VALUES ('jbloggs', 'foo');
-- Regardless, end the transaction:
END;
en cuenta que es no suficiente para simplemente bloquear la fila correspondiente en users
con SELECT ... FOR UPDATE
- si la fila aún no existe, varios procesos concurrentes pueden informar simultáneamente que la fila no existe, y luego intentar inserciones simultáneas, lo que da como resultado transacciones fallidas y, por lo tanto, espacios de secuencia.
Cualquiera de los dos esquemas de bloqueo funcionará; lo importante es que cualquiera que intente crear una fila con el mismo nombre debe intentar bloquear el mismo objeto.
Ver también: http://stackoverflow.com/a/9985219/398670 –
Posible duplicado de [Huecos entre la identificación de la clave principal en la tabla sql] (http://stackoverflow.com/questions/39099905/gaps-between- primary-key-id-in-sql-table) – e4c5