2013-07-17 3 views
2

나는 데이터베이스 무결성에 대해 알게되었고 데이터를 일관된 상태로 유지하기 위해 여러 개의 명령문을 수행해야 할 경우 트랜잭션을 사용해야합니다. Database development mistakes made by application developers은 (지점 16, 선택한 답)어떤 트랜잭션이 데이터 무결성을 약화 시키는가?

Wikipedia는 예를 사용 식료품에

  1. 직불 $ 100를 지출 계정을
  2. 계정

확인에 신용 $ (100) 내가 비를 입금하려고하면 - 존재하는 계정 ID 및 제약 조건을 올바르게 사용하고 있습니다. 예외가 발생하고 catch하고 롤백 할 수 있습니다. 정전이 발생하면이 두 가지 변경 사항이 원자 적으로 보장됩니다. 내가 제대로 이해한다면


그러나, 그 자체로 거래는 모든 경우에 나에게 도움이되지 않습니다 :

  1. MySQL은 (예를 PHP와 MySQL과) : 시작 거래
  2. MySQL의 : 데이터를 선택합니다 테이블에서
  3. PHP : 선택된 데이터와 계산 상태
    • PHP : 상태가 유효하다면, 데이터를 삽입
    • PHP : (

쿼리를 함께 실행 될 수 있기 때문에이 작동하지 않습니다 원자 실패없이이 있다고 결정 그것의 PHP를 커밋 트랜잭션 그렇지 않으면, 데이터

  • MySQL을 삽입하지 않습니다 오류, 일부 SQL 제한 조건이 아님).

    둘째, 테스트 한 결과 트랜잭션은 동 기적으로 커밋되지만 비동기 적으로 시작할 수 있습니다. 트랜잭션을 시작하고 10 초 지연을 추가하면 느린 스크립트를 시작하여 그 시간에 다른 트랜잭션을 시작하고 커밋 할 수 있습니다. 동시 트랜잭션을 보여줍니다. 다른 인스턴스의 수정 사항을보기 전에 두 인스턴스가 동일한 데이터를 선택할 수 있습니다. 변경 사항 만이 원자 적으로 보장됩니다.


    그럼 어떻게해야합니까? 나는 테이블을 잠그는 것이 효과적이라고 생각하지만 그 좋은 습관은 무엇입니까? 일부 조건은 SQL로 단일 명령문에 기술 될 수 있지만 더 복잡한 명령문은 할 수 없습니다.

  • 답변

    1

    이것은 좋은 질문입니다. 당신이 조금 그것에 대해 생각해 왔음을 보여줍니다.

    데이터베이스가 데이터 종속성을 인식하지 못하기 때문에 설명하는 문제가 있습니다. 데이터베이스에서 코드는 일부 데이터를 선택하고 일부 데이터를 씁니다. 선택한 데이터를 기반으로 데이터를 쓰는 것만 알지 못합니다. 일반적으로 데이터 종속성에 대해 데이터베이스에 알려야합니다. 이것은 각 데이터베이스에서 다르게 수행됩니다.

    MySQL에 대해 언급했습니다. InnoDB는 SELECT ... FOR UPDATE을 지원합니다. 이렇게하면 다른 쿼리가 트랜잭션 격리 수준에 따라 리소스에 액세스 할 수 없도록 리소스에 대한 잠금이 발급됩니다.이렇게하면 동일한 리소스를 잠그고있는 경우 첫 번째 트랜잭션이 커밋 될 때까지 예제의 두 번째 트랜잭션을 실행할 수 없게됩니다. 어떤 리소스가 잠기는지는 데이터베이스에 달려 있습니다.

    예를 살펴 보겠습니다. 행을 잠 그려면 먼저 트랜잭션을 생성하고 같은과 데이터베이스를 쿼리합니다 : 호환되지 않는 잠금이 차단되도록 이러한 행을 잠급니다 선택

    select * from tableA where value > 50 for update 
    

    이. 그런 다음 PHP로 처리 할 수 ​​있습니다. 일단 준비가되면 다른 테이블에 행을 삽입 할 수 있습니다.

    이 시점에서 커밋하기 전에 모든 행이 잠길 것입니다. 이 행은 다른 클라이언트에서 사용할 수 없습니다. 따라서 트랜잭션 전체에 걸쳐 커밋되지 않은 읽기 전까지는 다른 클라이언트가 사용자가 터치 한 행을 읽을 수 없습니다. 예제에서이 작업을 수행하려면 2의 모든 SELECT 문에 select for update가 사용되는지 확인해야합니다.

    다른 방법으로 데이터베이스에 업데이트 문을 알리는 방법입니다. update 문을 실행하면 데이터가 무엇이라고 생각하는지 지정합니다. 데이터베이스가 일부 행을 업데이트하는 경우 다른 데이터가 변경되지 않았 음을 확신 할 수 있습니다. 예상 행 수를 업데이트하지 않으면 다른 사용자가 데이터를 변경했음을 알 수 있으며 예외를 처리해야합니다. 이것은 낙관적 동시성 (optimistic concurrency)이며, 아무도 데이터를 업데이트하지 않을 것이라고 추측합니다. 따라서 변경 작업을 수행하십시오. 그 후에 누군가가 실제로했는지 확인할 수 있습니다.

    update table set value = 'new value' where id = '1' and value = 'old value' 
    

    다른 데이터베이스가 당신에게이 두 가지 기본 개념에 대한 다른 옵션을 제공 : 나중에 다음

    select value from table where id = '1' 
    

    : 같은

    쿼리는 것이다. 예를 들어 낙관적 인 모델에서는 실제 값 대신 타임 스탬프 (또는 자동 증가) 값을 확인할 수 있습니다.

    +0

    흠, 이것이 단순한 경우에만 유용하다는 것을 이해한다면 (이는 질문하는 것이 아닙니다). 예를 들어,'SELECT ... FOR UPDATE'는 여러 번 중요 합니다만 한 행으로 작업 할 때만 작동합니다. 'select ... where value = old value'와 동일합니다. 잘 알고 있지만, 많은 데이터를 선택하고 그 결과를 계산하여 앞으로 나아갈 지 여부를 결정해야한다면 어떻게해야할까요? 이러한 경우 테이블 잠금이 허용됩니까 (매우 조심해야하는 것 같습니다)? – Raekye

    +0

    @Raekye 두 기법 모두 여러 행에 사용할 수 있지만 선택한 모든 행을 잠그기 때문에 업데이트에 대한 선택 작업이 훨씬 쉬워집니다. –

    +0

    여러 행 (심지어 테이블)에서 데이터를 선택하면 업데이트되지 않지만 조건을 계산하여 다른 행이 삽입되어야하는지 알 수 있습니다. – Raekye

    관련 문제