2015-01-15 3 views
2

C와 같은 POS 시스템을 가지고 있으며 오랜 시간 동안 문제가 없었습니다 (단지 POS 한 개였습니다). 그러나 요즘에는 시스템을 사용하는 4 POS가 있고 동일한 데이터베이스에 연결되어 있고 한 POS의 모든 판매는 다른 모든 판매가 이루어지는 동일한 감사 (테이블)로 이동합니다. 그래서이 시스템에서이 절차를 대기 시간으로 인해 SQL 서버에서 중복되는 것을 피하십시오.

  • 해당 번호 (NO 다음 tickt)에 1을 추가 (단순 SELECT와) 마지막 티켓 번호를 얻을 수

    1. 기능입니다.
    2. 이 티켓 번호 (터미널, 날짜 및 직원 코드 포함)를 알고리즘에 삽입하는 ID 코드를 생성합니다.
    3. 모든 필수 정보 (날짜, 고객, 직원, ID 코드 등)가있는 데이터베이스에 판매 기록을 삽입하십시오. .)() 간단한 삽입 INTO와

    하지만 터미널과 직원이 다르기 때문에 같은 티켓 번호를 가진 일부 판매, 다행히 티켓 ID 코드가 동일하지 않습니다 실현,하지만 어떻게 4 POS를 가진 이걸 피할 수 있니?

    편집 1 : 모든 POS 시스템, 듀얼 기능이이 모드의 모든 POS는 (그들은 모두 하나의 POS 등) 다른 모드 모든 POS에서 연속 티켓을 생성 한 모드 POS 판매는 중앙, 그리고에 그런 이유로 자신의 티켓 번호가 있으니 신원을 사용할 수 없습니다.

  • +1

    코드를 잘 나타내야합니다. – dario

    +5

    데이터베이스에는 단일 원자 작업에서 다음 번호를 생성하는'identity' 열이 있습니다. 두 작업이 동시에 발생하지 않는다고 보장 할 수 없기 때문에 다중 스레드 환경에서 직접 생성하지 마십시오. 데이터베이스가 식별자를 생성하도록하십시오. – David

    +0

    프로그래밍 방식으로 레코드 식별자를 만들지 마십시오. 데이터베이스가이를 처리하도록하고 (David은 말했듯이) 중요한 작업에 트랜잭션을 사용합니다. – Filburt

    답변

    3

    시퀀스를 사용하여 다음 티켓 번호를 생성하면됩니다.

    CREATE SEQUENCE Tickets 
        START WITH 1 
        INCREMENT BY 1; 
    

    다음 각 POS는

    SELECT NEXT VALUE FOR Tickets; 
    

    이 순서가 두 번 같은 수를 반환 결코 보장 할 수.

    +0

    그건 내가 부르는 우아한 해결책이다! 내가 가진 다른 문제들을 풀어 라. –

    +0

    @CesarRomeroo 아주 좋습니다. 나는 어떤 이유로 든 SEQUENCE에 대해 완전히 잊어 버렸습니다 ;-). 만약 당신이 어떤 이유로 든 INSERT에 실패하면 그 값은 이미 증가 될 것이라는 점에서 IDENTITY와 비슷한 방식으로 작동하는 것을 상기하는 것처럼 이것을 테스트해야합니다. 다음 번에. 나를 잘못 이해하지 마라. 이것이 작동한다면, 내가 권장 한 것 이상으로 그것을 사용하라. 특히 비 이상적인 상황에서 예상대로 실제로 작동하는지 테스트하기위한 충분한 테스트를 수행하십시오. 하지만 상관없이 +1 :-). –

    +0

    INSERT가 실패 할 경우 ALTER SECUENCE를 사용하려고 생각했지만 작동 할 수도 있지만 (엄청난 판매의 극단적 인 시나리오를 가정 할 때) 이로 인해 무언가를 잘못하려면 상당한 대기 시간이 발생할 수 있습니까? –

    0

    원자 단위 동작에서이 작업을 수행해야합니다. 따라서 모든 것을 트랜잭션으로 랩핑하고 테이블을 잠글 수 있습니다. See here 잠금 등에 대한 좋은 토론을 위해

    잠그기는 ​​모든 것이 완료 될 때까지 대기하는 동안 테이블이 시작되기를 기다리기 시작하기 때문에 다른 모든 작업의 ​​속도가 느려지므로 살 수있는 내용이 아닐 수 있습니다.

    은 데이터베이스에서 관리하고 고유 한 증가 숫자를 유지하는 열에서 identity을 사용해야합니다.

    기본 키를 만들 수도 있습니다 (가지고 계 셨음). 몇 가지 조합이 가능합니다. 그리고 각 POS 엔드 포인트에 대해 실행중인 번호를 유지하여 수행 방법에 대한 더 많은 데이터를 볼 수 있습니다. 그러나 여기에는 범위가 아닌 분석에 대한 정보가 더 많이 포함됩니다.

    0

    GUID PK로 변경할 수있는 경우 현재 접근 방식에서 벗어나는 것이 좋습니다.

    그러나 어떤 경우에는 재 설계가 불가능하다는 것을 알고 있습니다 (기존 데이터베이스에서 설명하는 것과 똑같은 시나리오가 있음). 이 경우

    , 당신은 안전하게 삽입 명령을 조합하여 UPDLOCK 테이블 힌트를 사용하여 가치를 극대화하고 필요한 경우 지역 변수에 새 기본 키 값을 검색 할 OUTPUT INSERTED 기능을 사용할 수 있습니다

    DECLARE 
        @PK Table (PK INT NOT NULL) 
    
    INSERT 
        INTO Audit (
         TicketNumber, 
         Terminal, 
         Date, 
         EmployeeCode, 
         Client, 
         IDCode, 
         ... other fields) 
        /* Record the new PK in the tablevariable */ 
    OUTPUT INSERTED.TicketNumber INTO @PK 
    SELECT IsNull(MAX(TicketNumber), 0) + 1, 
         @Terminal, 
         @Date, 
         @EmployeeCode, 
         @Client, 
         @IDCode, 
         ... other values 
        FROM Audit WITH (UPDLOCK) 
    
    DECLARE @TicketNumber INT 
    
        /* Move the new PK from the local tablevariable into a local variable for subsequent use */ 
    SELECT @TicketNumber = PK 
        FROM @PK 
    
    +0

    IDENTITY ID가 아닌 ID를 생성하고 즉시 검색하는이 방법은 SQL Server 2005에서 사용되지 않으며 'OUTPUT' 절이 도입되었습니다. 'OUTPUT INSERTED.TicketNumber INTO TempTableOrTableVariable (FieldName)'을 삽입에 추가하면됩니다. 또한, GUID의 무작위 성으로 인해 조각화를 줄이는'NEWSEQUENTIALID()'도 소개했습니다. PK가 클러스터 된 경우 특히 _ GUID PK를 권장하지 않습니다. GUID가 필요한 경우 클러스터되지 않은 고유 한 인덱스로 만듭니다. 응용 프로그램에서 조회를 위해 사용하지만 JOIN 등을 위해 Clustered INT PK를 사용합니다. –

    +0

    좋은 위치에 있지만 명확히하기 위해 다른 모든 티켓 데이터를 먼저 INSERT 한 다음 틱 번호를 사용할 수 있습니까? –

    +0

    @CesarRomeroo : 아니요,이 방법에서는 동시에 티켓 데이터를 삽입하고 한 트랜잭션 내에서 다음 사용 가능한 키를 모두 가져옵니다. struzky가 언급 한 OUTPUT INSERTED 메커니즘에 대해 잊어 버렸습니다. 이로 인해 작업이보다 효율적으로 수행됩니다. 나는이 정보로 곧 답변을 업데이트하고 몇 가지 샘플 컬럼을 추가하여 완전한 개념을 보여줄 것입니다. –

    1

    앞서 언급 한 것처럼 TicketNumber가 순차적이고 고유 한 경우 IDENTITY 필드가 이동하는 것처럼 들립니다.그러나 어떤 이유로 인해이를 방지하는 것이 있거나이 경우 너무 많은 변경이 필요한 경우 응용 프로그램을 사용하여 ID 코드 생성 프로세스 자체를 잠그면 프로세스 자체를 단일 스레드로 제한 할 수 있습니다 잠금 장치 (sp_getapplocksp_releaseapplock 참조). 응용 프로그램 잠금을 사용하면 임의의 개념을 중심으로 잠금을 만들 수 있습니다. 즉, @Resource을 "generate_id_code"로 정의하면 각 발신자가 자신의 차례를 기다리게됩니다.

    BEGIN TRANSACTION; 
        EXEC sp_getapplock @Resource = 'generate_id_code', @LockMode = 'Exclusive'; 
    
        ...current 4 steps to generate the ID Code... 
    
        EXEC sp_releaseapplock @Resource = 'generate_id_code'; 
        COMMIT TRANSACTION; 
    

    당신은/오류 관리 (링크 MSDN 설명서에 명시된 바와 같이) 자신을 롤백 할 필요가 있으므로 일반적인 TRY/CATCH에 넣어 : 그것은이 구조를 따를 것입니다. 그러나이 방법으로 상황을 관리 할 수 ​​있습니다.

    참고 :sp_getapplock/sp_releaseapplock 아껴서 사용해야합니다; 응용 프로그램 잠금은 확실히 (이 경우와 같이) 매우 유용 할 수 있지만 절대적으로 필요한 경우에만 사용해야합니다.

    +0

    그러면 SELECT 명령을 잠글 수도 있습니다 (이미 취소되어 이미 다른 티켓을 처리하고있는 동안 마지막 티켓 번호를 다시 얻으려는 의도)? –

    +1

    @CesarRomeroo 명령을 잠그지 않고 다른 프로세스가 요청한 것과 동일한'@ Resource' 값의 지점을 넘어서서 액세스를 잠급니다.이 저장 프로 시저를 사용하든, 아니면'@Resource와 함께 'sp_getapplock' '가치. 이것이 바로 게이트 키퍼이며 테이블에 행을 잠그지 않아도되는 이것의 아름다움입니다. "ID 코드 생성"프로세스를 단일 스레드로 만들면 속도가 약간 느려지지만 이는 요청에 고유 한 부분입니다. IDENTITY 필드를 테이블에 추가하면 대신 값. –

    +0

    @CesarRomeroo 의미, 4 POS 시스템이 모두이 동일한 proc을 동시에 호출하면 그 중 하나만이 잠금을 얻을 수 있습니다. 다른 3 개는이 하나가 끝나고 잠금을 해제 할 때까지 기다립니다. 그러면 다른 1 개는 잠금을 받고 다른 2 개는 여전히 대기합니다. 그러나 다른 3 개가 대기하는 동안 SELECT를 명시 적으로 실행하지 못하도록 차단되지 않고 SELECT가있는 행으로 넘어갈 수 없습니다. 따라서 다른 프로세스는 해당 테이블에서 SELECT 할 수 있습니다. –

    관련 문제