복붙노트

[SQL] 데이터베이스 트랜잭션이 경쟁 조건을 방지합니까?

SQL

데이터베이스 트랜잭션이 경쟁 조건을 방지합니까?

완전히 데이터베이스 시스템에서 트랜잭션이 무엇을 나에게 분명하지 않다. 나는 그들이 (하나 개의 계정에, 예를 들어 공제 돈을 다른에 추가) 완전히 업데이트 목록을 롤백 할 수 있습니다 알고 있지만, 그들은 모두 할 것입니다? 특히, 그들은 경쟁 조건을 방지 할 수 있습니다? 예를 들면 :

// Java/JPA example
em.getTransaction().begin();
User u = em.find(User.class, 123);
u.credits += 10;
em.persist(u); // Note added in 2016: this line is actually not needed
em.getTransaction().commit();

(나는 이것이 아마 단일 업데이트 쿼리로 기록 될 수 있습니다 알고 있지만, 그것은 항상 곁에 그렇지 않습니다)

이 코드는 경쟁 조건 보호 받고 있는가?

나는 주로 MySQL5 + 이노에 관심이 있지만, 일반적인 답변은 너무 환영합니다.

해결법

  1. ==============================

    1.TL / DR : 거래는 본질적으로 모든 경쟁 조건을 방지하지 않습니다. 당신은 여전히 ​​실제 데이터베이스 구현에 잠금, 중지 및 재시도 처리 또는 다른 보호 조치가 필요합니다. 거래는 모든 동시성의 영향으로부터 그들을 안전하게하는 쿼리에 추가 할 수있는 비밀 소스 아니다.

    TL / DR : 거래는 본질적으로 모든 경쟁 조건을 방지하지 않습니다. 당신은 여전히 ​​실제 데이터베이스 구현에 잠금, 중지 및 재시도 처리 또는 다른 보호 조치가 필요합니다. 거래는 모든 동시성의 영향으로부터 그들을 안전하게하는 쿼리에 추가 할 수있는 비밀 소스 아니다.

    격리 - 당신이 당신의 질문에 얻고있는 것은 ACID에서 I입니다. 학습 능력 순수한 생각은 트랜잭션이 모든 트랜잭션이 순차적으로 실행되는 것처럼 결과가 동일 그래서, 완벽한 절연을 제공해야한다는 것입니다. 거의 실제 RDBMS 구현의 경우 없습니다 현실에서, 기능 구현에 의해 변화하고, READ 저지른 같은 규칙이 약한 격리 수준을 사용하여 약화 될 수있다. 실제로 당신은 거래도 SERIALIZABLE 격리에서 모든 경쟁 조건을 방지한다고 가정 할 수 없다.

    일부 RDBMS에 다른 사람보다 더 강한 능력을 가지고있다. 예를 들어, PostgreSQL의 9.2 및 최신 아주 좋은 SERIALIZABLE 격리를 감지 (전부는 아니지만) 가능한 거래 사이의 상호 작용 모두를 중단하지만, 충돌 거래 중 하나 대부분. 그래서 아주 안전하게 병렬로 거래를 실행할 수 있습니다.

    거의, any3 경우, 시스템은 정말 완벽한 SERIALIZABLE 격리가 그 잠금 에스컬레이션 및 잠금 주문 교착 상태와 같은 문제를 포함 방지 가능한 모든 인종과 이상은.

    심지어 강력한 격리와 (PostgreSQL을 같은) 일부 시스템은 트랜잭션을 충돌보다는 그들을 기다리게 및 직렬을 실행이 중단됩니다. 앱은 무엇을하고 있었는지 기억하고 트랜잭션을 다시 시도해야합니다. 트랜잭션이 DB에 저장되지 동시성 관련 이상 현상을 방지하고있다 그래서 동안, 그것은 응용 프로그램에 투명하지 않은 방식으로 그렇게 끝났다.

    확실하게 데이터베이스 트랜잭션의 주요 목적은 원자 커밋을 제공한다는 것입니다. 당신은 트랜잭션을 커밋 할 때까지 변경 사항이 적용되지 않습니다. 커밋하면은 지금까지 다른 트랜잭션에 관한 한 같은 순간에 모든 테이크 효과를 변경합니다. 어떤 트랜잭션은 이제까지 단지 일부가 트랜잭션 makes1,2 변경으로 볼 수 있습니다. 마찬가지로, 만약 ROLLBACK, 지금까지 다른 트랜잭션에 의해 들키지 트랜잭션의 변경 후 없음; 거래가 존재하지 않았던 것처럼입니다.

    즉 ACID의 A입니다.

    ACID의 D - 또 다른 내구성이다. 그것은 당신이 트랜잭션을 커밋 할 때 진정으로 전력 손실 또는 갑자기 재부팅과 같은 오류를 살아남을 것입니다 스토리지에 저장되어야 함을 지정합니다.

    위키 백과 참조

    오히려 잠금 및 / 또는 높은 격리 수준을 사용하는 것보다, 낙관적 동시성 제어를 사용하는 등 최대 절전 모드, EclipseLink가 같은으로 ORMs에 대한 그것의 일반적인 성능을 유지하면서 약한 격리 수준의 한계를 극복하기 위해 (종종 "낙관적 잠금"이라고합니다).

    이 방법의 핵심 기능은 당신이 큰 여러 트랜잭션에 걸쳐 플러스 높은 사용자 수를 가지고 특정 사용자와의 상호 작용 사이의 긴 지연이있을 수 있습니다 시스템 작업을 걸쳐 수 있다는 것입니다.

    인 - 텍스트 링크뿐만 아니라, 잠금, 차단 및 동시성에 PostgreSQL의 문서 장을 참조하십시오. 다른 RDBMS를 사용하는 경우에도 당신은 그것을 설명하는 개념에서 많은 것을 배울 수 있습니다.

    편의상 여기에 거의 실행되지 READ UNCOMMITTED 격리 수준을 무시 1I'm; 그것은 더러운 읽기 허용합니다.

    2AS는 점 밖으로 @meriton의 추론은 반드시 사실이 아니다. 팬텀은 SERIALIZABLE 아래 아무것도에서 발생 읽습니다. 진행중인 거래의 한 부분은 다음에 진행중인 트랜잭션의 다음 부분이 때 다른 트랜잭션 커밋 변경 사항을 참조 않는 (하지 않은 아직 커밋 된 트랜잭션에 의해) 일부 변경 사항을 확인하지 않습니다.

    3 음, IIRC SQLite2는 쓰기가 시도 전체 데이터베이스를 잠금 덕분에 않지만, 그게 내가 동시성 문제에 대한 이상적인 솔루션이라고 부르는이 아니다.

  2. ==============================

    2.다양한 각도로 트랜잭션의 데이터베이스 계층 지원의 자성라는 격리 수준. 지원하는 격리 수준에 대한 데이터베이스 관리 시스템, 자신의 트레이드 오프의 설명서를 참조하십시오. 가장 강력한 격리 수준, 직렬화, 그들은 하나 하나 실행하는 것처럼 실행 트랜잭션을 필요로한다. 이것은 일반적으로 데이터베이스에 배타적 잠금을 사용하여 구현됩니다. 이것은 어떤 관련 트랜잭션을 롤백하여 원인 교착 상태, 데이터베이스 관리 시스템의 감지 및 수정 될 수 있습니다. 이러한 접근 방식은 종종 비관적 잠금이라고합니다.

    다양한 각도로 트랜잭션의 데이터베이스 계층 지원의 자성라는 격리 수준. 지원하는 격리 수준에 대한 데이터베이스 관리 시스템, 자신의 트레이드 오프의 설명서를 참조하십시오. 가장 강력한 격리 수준, 직렬화, 그들은 하나 하나 실행하는 것처럼 실행 트랜잭션을 필요로한다. 이것은 일반적으로 데이터베이스에 배타적 잠금을 사용하여 구현됩니다. 이것은 어떤 관련 트랜잭션을 롤백하여 원인 교착 상태, 데이터베이스 관리 시스템의 감지 및 수정 될 수 있습니다. 이러한 접근 방식은 종종 비관적 잠금이라고합니다.

    (JPA 제공자 포함) 대부분의 객체 관계형 매퍼는 업데이트 충돌이 다음 롤 트랜잭션을 애플리케이션 계층에서 데이터베이스에 방지하지만 검출되지 않는 낙관적 잠금을 지원합니다. 당신이 낙관적 잠금이 설정 한 경우, 귀하의 예제 코드의 전형적인 실행은 다음과 같은 SQL 쿼리를 방출합니다 :

    select id, version, credits from user where id = 123;  
    

    하자이 반환 (123, 13, 100)을 말한다.

    update user set version = 14, credit = 110 where id = 123 and version = 13;
    

    데이터베이스는 우리에게 업데이트 된 행 수를 알려줍니다. 그것은 하나 경우, 충돌 업데이트가 없었다. 제로라면, 충돌하는 업데이트가 발생하고, JPA 제공 할 것입니다

    rollback;
    

    응용 프로그램 코드를 재 시도에 의해 예를 들어, 실패한 트랜잭션을 처리 할 수 ​​있도록 예외를 throw합니다.

    요약 : 두 접근 방식으로, 당신의 문이 경쟁 조건에서 안전 할 수있다.

  3. ==============================

    3.이는 (일반적으로 직렬화 고립 레벨 트랜잭션이 트랜잭션되도록, 즉 동일한 행을 수정 순서대로 처리 paralell에 (또는 적어도 배타적 로킹 사용하지 이래로, 경쟁 상태를 방지 할 직렬화에서 수행되는 분리 레벨에 따라 순서). (선택한 레코드를 쓰기 잠금을 사들 문 '업데이트 ... 선택'예 지원에 대한 MySQL의) 기록을 잠글 더 나은 수동으로 경쟁 조건을 방지하기 위해

    이는 (일반적으로 직렬화 고립 레벨 트랜잭션이 트랜잭션되도록, 즉 동일한 행을 수정 순서대로 처리 paralell에 (또는 적어도 배타적 로킹 사용하지 이래로, 경쟁 상태를 방지 할 직렬화에서 수행되는 분리 레벨에 따라 순서). (선택한 레코드를 쓰기 잠금을 사들 문 '업데이트 ... 선택'예 지원에 대한 MySQL의) 기록을 잠글 더 나은 수동으로 경쟁 조건을 방지하기 위해

  4. ==============================

    4.그것은 특정의 RDBMS에 따라 달라집니다. 질의 평가 계획 중에 결정으로 일반적으로 트랜잭션이 잠금을 획득. 몇몇 CAN 요청 테이블 레벨 잠금, 다른 열 레벨, 다른 레코드 레벨, 제 성능에 바람직하다. 귀하의 질문에 짧은 대답은 '예'입니다.

    그것은 특정의 RDBMS에 따라 달라집니다. 질의 평가 계획 중에 결정으로 일반적으로 트랜잭션이 잠금을 획득. 몇몇 CAN 요청 테이블 레벨 잠금, 다른 열 레벨, 다른 레코드 레벨, 제 성능에 바람직하다. 귀하의 질문에 짧은 대답은 '예'입니다.

    즉, 트랜잭션이 그룹에 쿼리의 집합을 의미하고 원자 작업로를 나타냅니다. 작업이 실패 할 경우 변경 사항이 rolledback 있습니다. 나는 정확하게 당신이 사용하고있는 어댑터가 무엇을하는지 모르겠지만, 트랜잭션의 정의에 부합하는 경우는 잘해야합니다.

    이 경쟁 조건의 예방을 보장하지만, 명시 적으로 기아 또는 교착 상태를 방지하지 않습니다. 트랜잭션 잠금 관리자는 담당하고있다. 테이블 잠금은 가끔 사용하지만, 그들은 동시 작업의 수를 감소의 상당한 가격으로 제공됩니다.

  5. from https://stackoverflow.com/questions/6477574/do-database-transactions-prevent-race-conditions by cc-by-sa and MIT license