2009-09-22 4 views
4

트랜잭션 RDBMS 사용에 익숙하지만 트랜잭션이 실패 할 경우 내 메모리 데이터의 변경 사항을 롤백하는 방법은 무엇입니까? 데이터베이스를 사용하지 않는다면 어떨까요?메모리 내 프로세스를 트랜잭션 화하려면 어떻게해야합니까?

여기에 인위적인 예입니다 : 내 예에서

public void TransactionalMethod() 
{ 
    var items = GetListOfItems(); 

    foreach (var item in items) 
    {  
     MethodThatMayThrowException(item); 

     item.Processed = true; 
    } 
} 

, 어떻게 든 롤백 할 목록의 항목에 대한 변경을 할 수 있습니다,하지만 난이 어떻게 달성 할 수 있습니까?

나는 "소프트웨어 트랜잭션 메모리"에 대해 알고 있지만 그것에 대해 많이 알지 못하며 상당히 실험적으로 보입니다. 나는 "compensatable transactions"개념을 알고 있지만 do/undo 코드를 작성하는 오버 헤드가 발생합니다.

Subversion은 "정리"명령을 실행하여 작업 복사본을 업데이트하는 중 오류를 처리하는 것으로 보입니다.

아이디어가 있으십니까?

UPDATE : 커밋에 원본 데이터의 사본에

일 업데이트 :
Reed Copsey 포함 an excellent answer을 제공합니다.

이 더 내 질문에 한 단계 소요 - 오류가 커밋 동안 어떤 일이 발생하는지 경우? 우리는 커밋을 즉각적인 작업이라고 생각하기는하지만 사실 많은 데이터를 많이 변경하는 경우가 있습니다. 커밋이 적용되는 동안 어쩔 수없는 일, 예 : OutOfMemoryException이 발생하면 어떻게됩니까? 하나는 롤백 옵션에가는 경우 롤백 동안 예외 이 있는지 역설적으로에

은 어떻게됩니까? 오라클 RDBMS에는 롤백 세그먼트와 UNDO 로그 및 사물의 개념이 있지만 디스크에 직렬화가 없다고 가정하면 (디스크에 직렬화되지 않으면 발생하지 않음) 충돌이 발생하면 해당 로그를 조사 할 수 있습니다 그리고 그것을 복구하십시오.) 이것이 정말로 가능합니까?

UPDATE 2 Alex에서
answer는 좋은 제안했다 : 즉 하나가 다른 목적은, 다음에, 커밋 단계 단순히 새로운 객체를 통해 현재 오브젝트에 대한 참조를 변화 갱신한다. 그는 당신이 변경 한 객체가 실제로 수정 된 객체의 목록이라는 제안을하기 위해 나아갔습니다.

나는 그가 (내가 생각하는) 무슨 말을 이해, 나는 결과로 문제는 더 복잡하게하려면 :

이 시나리오를 부여하는 방법,

, 당신은 잠금 처리합니까?

var customers = new Dictionary<CustomerKey, Customer>(); 

지금, 당신은 어떻게 잠금 및 전체 목록을 교체하지 않고 변경 사항을 적용 할, 고객들 중 일부를 변경하려면 : 당신은 고객의 목록을 상상해? 예 :

var customerTx = new Dictionary<CustomerKey, Customer>(); 

foreach (var customer in customers.Values) 
{ 
    var updatedCust = customer.Clone();  
    customerTx.Add(GetKey(updatedCust), updatedCust); 

    if (CalculateRevenueMightThrowException(customer) >= 10000) 
    { 
     updatedCust.Preferred = true; 
    } 
} 

커밋하는 방법은 무엇입니까?이 (알렉스의 제안은) 목록 참조를 교체하는 동안 모든 고객 잠금 의미합니다 :

lock (customers) 
{ 
    customers = customerTx; 
} 

반면 I 루프를 통해 원래 목록에서 참조 수정, 그것은 원자하지 않은 그리고 파울 떨어지면 "

foreach (var kvp in customerTx) 
{ 
    customers[kvp.Key] = kvp.Value; 
} 

답변

8

거의이 작업을 수행하는 모든 옵션은 세 가지 기본 방법 중 하나가 필요합니다 :

  1. 엄마는 "문제 도중에 충돌하는 경우 어떻게 변경하기 전에 데이터 사본을 저장하고 중단 된 경우 롤백 상태로 되돌립니다.
  2. 데이터 사본에서 작업하고 커밋시 원본을 업데이트하십시오.
  3. 데이터가 변경된 경우 로그를 남기고 중단 한 경우 실행 취소하십시오.

예를 들어 언급 한 Software Transactional Memory은 세 번째 방법을 따릅니다. 좋은 점은 데이터를 낙관적으로 처리하고 성공적인 커밋에 대한 로그를 버리는 것입니다.

+0

그래, 내 질문의 핵심은 그 커밋/롤백 단계에서 일어나는 일이다. 커밋 중에 예외가 *있는 경우는 어떨까요? 그렇다면 부분적인 변화가있었습니다. 데이터를 오브젝트 목록에 강제로 넣을 수는 있지만, 잠긴 시나리오로 들어가서 질문을 업데이트했습니다. 나는 실제 커밋/롤백 작업 자체를 실제로 확대하는 것에 대해 이야기하고 있습니다. ** 실패한 경우 ** 어떻게 대처하는지보십시오. –

+0

여기에는 많은 옵션이 있습니다. 일반적인 커밋/롤백 스키마에 대한 데이터베이스 이론과 연습을 살펴 보겠다.하지만 전체 복사본 작업을 수행하고 마지막에는 참조를 전환하거나 전체 개체 (예 : 고객 잠금)를 잠그는 등의 작업을 수행하는 경우가 많습니다. , 그것은 거대한 분야입니다. 구체적인 질문없이 자세하게 설명하기는 어렵습니다. –

0
public void TransactionalMethod() 
{ 
    var items = GetListOfItems(); 

    try { 
     foreach (var item in items) 
     {   
      MethodThatMayThrowException(item); 

      item.Processed = true; 
     } 
    } 
    catch(Exception ex) { 
     foreach (var item in items) 
     { 
      if (item.Processed) { 
       UndoProcessingForThisItem(item); 
      } 
     } 
    } 
} 

분명히 "실행 취소 ..."의 구현은 독자를위한 연습으로 남겨 둡니다.

+0

예, 많은 의미가 있습니다. 나는 그런 식으로 구현하려고 생각했지만, 내게 순수 주의자는 "롤백 중에 예외가 발생하면 어떻게 될까요?"라고 묻습니다. 그 시나리오에 어떻게 대처 하시겠습니까? –

+0

@Neil - 글쎄, 게임이 맞지 않아? 메모리에서 작업하기 때문에 I/O 예외가 아닌 응용 프로그램 예외가 발생할 가능성이 큽니다. 메모리 예외가 발생할 수 있지만 솔직히 실제 문제가 발생하면 메모리 예외가 발생할 수 있습니다. 예를 들어, 비록 당신이 OOM 예외에 대처할 수있을지라도, 대부분의 라이브러리는 예를 들어 할 수 없습니다. 그러나 어쨌든, 분명히 이것은 모든 것을 어렵게 만드는 측면입니다. 당신이 "이미 해냈다"고 생각하기 때문에, "되돌리기"는 안전해야하므로 위험은 낮지 만 코드 만 확실히 알 수 있습니다. 23 개의 문자가 남았습니다. –

1

질문 :

"커밋 중에 오류가 발생하면 어떻게해야합니까?"

중요하지 않습니다. 당신은 어딘가에/메모리에 무언가를 저지르고, 작업이 성공하면 그 동안 점검 할 수 있습니다. 그 경우, 의도 한 오브젝트 (오브젝트 A)의 참조을 사용자가 확약 한 (오브젝트 B)로 변경하십시오. 그런 다음에는 failsafe 커밋이 있습니다. 참조는 성공적인 커밋에서만 업데이트됩니다. 참조 변경은 원 자성입니다.

+0

예, * 단일 * 참조 변경은 원 자성입니다. 그러나 참조 목록이 있고 예외가 발생했을 때 커밋 단계에서 업데이트하는 것이 중간에 있었습니까? –

+0

틀렸어. 항상 업데이트 할 참조는 하나뿐입니다. 다른 모든 참조는 객체 B에서 객체 X, Y, Z까지 이전 커밋 단계에서 설정되었습니다. 오브젝트 B가 실제로 필요한 것을 실제로 확인했으면 B에 대한 참조를 설정하고 자신이 참조하는 모든 항목에 대한 전체 액세스 권한을 얻습니다. – Alex

+0

명확히하기 위해 오브젝트 B는 루트 인스턴스이며, 당신이 이미 그것을 가지고 있지 않다면 래퍼를 통해 항상 확립 할 수 있습니다. 임의의 수의 자손 관계를 항상 1 개의 루트로 가져올 수 있습니다. 그 결과 단일 참조 정보가 업데이트됩니다. – Alex

관련 문제