Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
En un entorno de operación simultánea de bases de datos, varias transacciones que intentan actualizar los mismos datos al mismo tiempo pueden causar conflictos. PostgreSQL proporciona una serie de mecanismos para manejar estos conflictos de actualizaciones simultáneas para garantizar la coherencia e integridad de los datos.
Pueden ocurrir conflictos de actualización simultánea cuando dos o más transacciones intentan modificar la misma fila de datos al mismo tiempo. Los escenarios comunes incluyen:
PostgreSQL utiliza principalmente MVCC (Control de concurrencia multiversión) para manejar transacciones concurrentes. MVCC permite que una transacción lea una versión de datos que cumpla con sus requisitos de nivel de aislamiento sin bloquear para bloquear las operaciones de lectura de otras transacciones. Sin embargo, es posible que aún se produzcan conflictos durante las operaciones de escritura.
PostgreSQL utiliza varios tipos de bloqueos para controlar el acceso simultáneo a los datos. Los tipos de bloqueo comunes incluyen:
La granularidad del bloqueo puede ser a nivel de fila (Nivel de fila), a nivel de página (Nivel de página) y a nivel de tabla (Nivel de tabla).
PostgreSQL admite cuatro niveles de aislamiento de transacciones:
Un método sencillo es hacer que la transacción se vuelva a intentar cuando se produzca un conflicto. Los ejemplos son los siguientes:
DO
$$
DECLARE
conflict_detected BOOLEAN := FALSE;
BEGIN
LOOP
-- 尝试执行更新操作
UPDATE products SET price = 100 WHERE id = 1;
-- 检查是否有冲突(例如,通过检查受影响的行数)
IF NOT FOUND THEN
conflict_detected := TRUE;
ELSE
EXIT;
END IF;
-- 若有冲突,等待一段时间并重试
IF conflict_detected THEN
PERFORM pg_sleep(1);
END IF;
END LOOP;
END;
$$;
En el ejemplo anterior, si la operación de actualización no afecta a ninguna fila (lo que indica que puede haber un conflicto), se establece un indicador, se espera un período de tiempo y luego se vuelve a intentar.
El control de concurrencia optimista supone que rara vez ocurren conflictos de concurrencia. En este método, la transacción no se bloquea al actualizar los datos, pero verifica si los datos han sido modificados por otras transacciones al confirmar. Si no hay conflictos, la transacción se confirma correctamente; si hay conflictos, la transacción se revierte y se vuelve a intentar según sea necesario.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
En el ejemplo anterior, la operación de actualización tiene éxito sólo si los datos no han sido modificados por otras transacciones.
El control de concurrencia pesimista supone que es probable que se produzcan conflictos de concurrencia y adquiere los bloqueos necesarios durante la ejecución de la transacción para bloquear otras transacciones potencialmente conflictivas.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
Agregue un campo de versión a la tabla para realizar un seguimiento de los cambios en los datos.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
Al actualizar datos, incremente también el campo de versión:
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
Si el número de filas afectadas por la actualización es 0, existe un conflicto porque la versión esperada no coincide con la versión real.
Agregue un campo de marca de tiempo a cada fila de datos para registrar la hora de la última modificación de los datos.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Al actualizar, actualice solo los datos con una marca de tiempo anterior a la marca de tiempo leída por la transacción actual:
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
Supongamos que tenemos un sistema de gestión de inventario para una tienda online con un inventory
tabla para almacenar cantidades de inventario de artículos.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Ahora hay dos transacciones simultáneas:
Transacción 1:
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设读取到的数量为 10
UPDATE inventory SET quantity = 5 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Transacción 2:
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设也读取到的数量为 10
UPDATE inventory SET quantity = 8 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Si estas dos transacciones se ejecutan casi al mismo tiempo, puede ocurrir un conflicto.
Si utilizamos la resolución de conflictos basada en marcas de tiempo:
T1
)。T2
)。Cuando la transacción 1 intenta actualizar, si ninguna otra transacción ha modificado los datos desde que los leyó (es decir, last_updated <= T1
), la actualización se realizó correctamente.
Cuando la transacción 2 intenta actualizar, si encuentra que los datos last_updated
más que elT2
(Lo que indica que se modificó después de que la transacción 2 lo leyó), la actualización falla y la transacción 2 puede optar por revertir e intentar nuevamente, o realizar otro procesamiento de acuerdo con la lógica empresarial.
🎉相关推荐