문제

MySQL과 PHP + Propel 1.3을 사용하는 동안 동시성 문제가 발생하는 것 같습니다.다음은 Propel 객체의 "save" 메소드에 대한 간단한 예입니다.

public function save(PropelPDO $con = null) {
    $con = Propel::getConnection();
    try {
        $con->beginTransaction();
        sleep(3); // ignore this, used for testing only
        parent::save($con);
        $foo = $this->getFoo(); // Propel object, triggers a SELECT

        // stuff is happening here...

        $foo->save($con);
        $con->commit();
    } catch (Exception $e) {
        $con->rollBack();
        throw $e;
    }
}

문제는 $foo 객체입니다.아주 짧은 시간에 예제 메서드를 두 번 차례로 호출한다고 가정해 보겠습니다.어떤 경우에는 두 번째 트랜잭션이 $foo를 읽으면...

$foo = $this->getFoo();

...첫 번째 거래가 저장될 기회를 갖기 전에...

$foo->save($con);

...두 번째 트랜잭션에서 읽은 $foo는 오래되어 나쁜 일이 발생할 것입니다.

첫 번째 트랜잭션이 작업을 마친 후에만 후속 트랜잭션을 읽을 수 있도록 Foo 객체가 저장된 테이블을 강제로 잠그려면 어떻게 해야 합니까?

편집하다:컨텍스트는 웹 애플리케이션입니다.간단히 말해서, 어떤 경우에는 첫 번째 요청에서 일부 데이터 수정($foo를 가져오고 저장하는 사이에 발생)을 수행하기를 원합니다.모든 후속 요청에서는 수정이 불가능해야 합니다.수정 여부는 가져온 $foo 상태(테이블 행 속성)에 따라 다릅니다.두 개의 트랜잭션이 동일한 $foo를 가져오면 수정이 두 번 발생하여 문제가 발생합니다.

도움이 되었습니까?

해결책

이 기존 행을 화면/응용 프로그램에 로드할 때 LastChgDate도 로드하세요.저장할 때 "AND LastChgDate=가치".업데이트의 영향을 받은 행 수를 확인하고, 0이면 "다른 사람이 이미 이 레코드를 저장했습니다"라는 오류를 반환하고 롤백 및 기타 변경 사항을 반환합니다.이 논리를 적용하면 행을 로드할 때와 동일한 경우에만 행을 저장할 수 있습니다.새 행인 INSERT의 경우 새 행이므로 필요하지 않습니다.

다른 팁

MySQL에서는 SELECT FOR UPDATE를 사용하여 잠금을 수행할 수 있다고 생각합니다.

또 다른 옵션은 GET_LOCK 및 RELEASE_LOCK MySQL 함수 호출을 사용하여 리소스에 대한 액세스를 제어하는 ​​데 사용할 명명된 잠금을 생성하는 것입니다.

이러한 접근 방식에는 몇 가지 단점이 있습니다.나는 그것들을 많이 사용하지 않았고 그것들은 MySQL에 특화되어 있지만 당신에게 도움이 될 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top