문제

PayPal Instant 지불 알림을받을 때 제품 (배송 보험 정책과 같은)을 만들어야하는 응용 프로그램을 연구하고 있습니다. 불행히도 PayPal은 때때로 중복 알림을 보냅니다. 또한 PayPal에서 업데이트를받을 때 웹 서비스 업데이트를 동시에 수행하는 또 다른 타사가 있습니다.

다음은 관련된 데이터베이스 테이블의 기본 다이어그램입니다.

// table "package"
// columns packageID, policyID, other data...
// 
// table "insurancepolicy"
// columns policyID, coverageAmount, other data...

다음은 내가하고 싶은 일의 기본 다이어그램입니다.

using (SqlConnection conn = new SqlConnection(...))
{
  sqlTransaction sqlTrans = conn.BeginTransaction(IsolationLevel.RepeatableRead);

  // Calls a stored procedure that checks if the foreign key in the transaction table has a value.
  if (PackageDB.HasInsurancePolicy(packageID, conn))
  { 
    sqlTrans.Commit();
    return false;
  }

  // Insert row in foreign table.
  int policyID = InsurancePolicyDB.Insert(coverageAmount, conn);
  if (policyID <= 0)
  {
    sqlTrans.Rollback();
    return false;
  }

  // Assign foreign key to parent table.  If this fails, roll back everything.
  bool assigned = PackageDB.AssignPolicyID(packageID, policyID, conn);
  if (!assigned)
  {
    sqlTrans.Rollback();
    return false;
  }
}

이 작업을 동시에 수행하는 두 개의 (또는 그 이상) 스레드 (또는 프로세스 또는 응용 프로그램)가있는 경우 정책이 만들어지고 정책이 할당 될 때까지 첫 번째 스레드가 정책 정보가없는 상태에서 "패키지"행을 잠그는 것을 원합니다. 패키지 테이블에. 그런 다음 PolicyID가 패키지 테이블에 할당 된 후 잠금이 해제됩니다. 이 동일한 코드를 호출하는 다른 스레드가 패키지 행을 읽을 때 정책 ID가 없는지 확인할 때 일시 중지되기를 바랍니다. 첫 번째 트랜잭션의 잠금 장치가 릴리스되면 두 번째 트랜잭션이 정책 ID가 있음을 알기를 바랍니다. 따라서 정책 테이블에 행을 삽입하지 않고 반환합니다.

참고 : CRUD 데이터베이스 설계로 인해 저장된 각 절차에는 읽기 (선택), 작성 (삽입) 또는 업데이트가 포함됩니다.

이것이 반복적 인 트랜잭션 격리의 올바른 사용입니까?

감사.

도움이 되었습니까?

해결책

더 안전하고 깨끗합니다 insert into Policy 중복을 삽입하려는 시도에서 일부 독창성 테이블 제약 조건을 누르십시오. 격리 수준을 높이면 동시성을 낮추고 교착 상태와 같은 다른 불쾌한 문제로 이어질 수 있습니다.

또 다른 방법은 항상 정책 행을 삽입 한 다음 패키지가 이미 정책에 첨부 된 경우 다시 롤백하는 것입니다.

begin tran (read committed)

/* tentatively insert new Policy */
insert Policy

/* attach Package to Policy if it's still free */
update Package
  set Package.policy_id = @policy_id
  where Package.package_id = @package_id and Package.policy_id is null

if @@rowcount > 0
  commit
else
  rollback

이것은 갈등이 드물면 가장 잘 작동합니다. 이는 귀하의 경우 인 것 같습니다.

다른 팁

나는 당신이 실제로 직렬화 가능한 격리 수준을 원한다고 생각합니다. 문제는 두 개의 스레드가 HasinsuransurePolicyCheck을 지나갈 수 있다는 것입니다.

당신은 이것에 대한 다른 많은 옵션이 있습니다. 하나는 메시지 대기열을 사용하고 이러한 요청을 직접 처리하고 있습니다. 다른 하나는 사용하는 것입니다 sp_getApplock 그리고 그 패키지의 고유 한 키를 잠그십시오. 그렇게하면 더 이상 행이나 테이블을 잠그지 않아야합니다.

Aaronjensen의 응답에서 "메시지 큐"아이디어에 동의합니다. 동일한 데이터 행을 동시에 업데이트하려고 시도하는 여러 동시 스레드가 우려되는 경우 대신 스레드가 데이터를 작업 대기열에 삽입 한 다음 단일 스레드에 의해 순차적으로 처리됩니다. 대상 테이블은 "N"대신 하나의 스레드 만 업데이트되고 작업 대기열 작업은 메시징 스레드의 삽입으로 제한되고 데이터 처리 스레드의 읽기/업데이트로 제한되기 때문에 데이터베이스의 경합이 크게 줄어 듭니다.

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