내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
데이터베이스 동시 운영 환경에서는 동일한 데이터를 동시에 업데이트하려는 여러 트랜잭션이 충돌을 일으킬 수 있습니다. PostgreSQL은 데이터 일관성과 무결성을 보장하기 위해 이러한 동시 업데이트 충돌을 처리하는 일련의 메커니즘을 제공합니다.
두 개 이상의 트랜잭션이 동시에 동일한 데이터 행을 수정하려고 시도하면 동시 업데이트 충돌이 발생할 수 있습니다. 일반적인 시나리오는 다음과 같습니다.
PostgreSQL은 주로 MVCC(Multiversion Concurrency Control)를 사용하여 동시 트랜잭션을 처리합니다. MVCC를 사용하면 트랜잭션이 다른 트랜잭션의 읽기 작업을 차단하기 위해 잠그지 않고도 격리 수준 요구 사항을 충족하는 데이터 버전을 읽을 수 있습니다. 그러나 쓰기 작업 중에 충돌이 계속 발생할 수 있습니다.
PostgreSQL은 여러 유형의 잠금을 사용하여 데이터에 대한 동시 액세스를 제어합니다. 일반적인 잠금 유형은 다음과 같습니다.
잠금 세분성은 행 수준(행 수준), 페이지 수준(페이지 수준) 및 테이블 수준(테이블 수준)일 수 있습니다.
PostgreSQL은 네 가지 트랜잭션 격리 수준을 지원합니다.
간단한 접근 방식은 충돌이 발생할 때 트랜잭션을 다시 시도하는 것입니다. 예는 다음과 같습니다:
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;
$$;
위의 예에서 업데이트 작업이 행에 영향을 주지 않으면(충돌이 있을 수 있음을 나타냄) 플래그가 설정되고 일정 시간 동안 기다린 후 다시 시도됩니다.
낙관적 동시성 제어에서는 동시성 충돌이 거의 발생하지 않는다고 가정합니다. 이 방법은 데이터를 업데이트할 때 트랜잭션을 잠그지 않고 커밋할 때 다른 트랜잭션에 의해 데이터가 수정되었는지 확인합니다. 충돌이 없으면 트랜잭션이 성공적으로 커밋됩니다. 충돌이 있으면 트랜잭션이 롤백되고 필요에 따라 다시 시도됩니다.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
위의 예에서 업데이트 작업은 다른 트랜잭션에 의해 데이터가 수정되지 않은 경우에만 성공합니다.
비관적 동시성 제어는 동시성 충돌이 발생할 가능성이 있다고 가정하고 트랜잭션 실행 중에 필요한 잠금을 획득하여 잠재적으로 충돌할 수 있는 다른 트랜잭션을 차단합니다.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
데이터 변경 사항을 추적하려면 테이블에 버전 필드를 추가하세요.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
데이터를 업데이트할 때 버전 필드도 증가시킵니다.
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
업데이트의 영향을 받는 행 수가 0인 경우 예상 버전과 실제 버전이 일치하지 않아 충돌이 발생합니다.
데이터의 마지막 수정 시간을 기록하려면 데이터의 각 행에 타임스탬프 필드를 추가하세요.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
업데이트할 때 현재 트랜잭션에서 읽은 타임스탬프보다 오래된 타임스탬프가 있는 데이터만 업데이트하세요.
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
다음과 같은 온라인 상점의 재고 관리 시스템이 있다고 가정해 보겠습니다. inventory
품목의 재고 수량을 저장하는 테이블입니다.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
이제 두 개의 동시 트랜잭션이 있습니다.
거래 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;
거래 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;
이 두 트랜잭션이 거의 동시에 실행되면 충돌이 발생할 수 있습니다.
타임스탬프 기반 충돌 해결을 사용하는 경우:
T1
)。T2
)。트랜잭션 1이 업데이트를 시도할 때 데이터를 읽은 이후 다른 트랜잭션이 데이터를 수정하지 않은 경우(예: last_updated <= T1
), 업데이트가 성공했습니다.
트랜잭션 2가 업데이트를 시도할 때 데이터가 last_updated
그 이상T2
(트랜잭션 2가 읽은 후 수정되었음을 나타냄) 업데이트가 실패하고 트랜잭션 2는 롤백하고 다시 시도하거나 비즈니스 로직에 따라 다른 처리를 수행하도록 선택할 수 있습니다.
🎉相关推荐