CI 묻고 답하기

제목 안녕하세요 트랜잭션의 동시성에 대해서 질문드립니다.
카테고리 CI 2, 3
글쓴이 Wally 작성시각 2020/11/25 17:47:20
댓글 : 10 추천 : 0 스크랩 : 0 조회수 : 7830   RSS

안녕하세요 선배님 

CI로 예약 프로젝트를 진행중에 동시성에 오류가 있는 부분이 있어 궁금하여 질문합니다.

 

##상황##

상황은 A와 B가 동시에 예약을 등록하는 상황에서 발생하는데요.

입력 로직의 플로우는 체크1(select)->체크2(select)->등록(insert)라는 플로우인데요

A와 B가 동시에 예약을 등록하면 A의 요약은 체크1, 체크2를 통과하여 등록까지 문제없이 진행됩니다.

그러나 문제는 동시에 입력된 B의 경우는 새롭게 입력된 A의 예약정보를 반영해서 의체크1에서 예외처리가 되어야하지만 그대로 등록되어 버리는 문제가 발생합니다.

(checkA,checkB,insertA는 모두 같은 테이블을 사용하고 있습니다.)

 

##코드##

ccontroller 1{

     model1->check A()

     model2->check B()

     model3->insert A()

}

model1{

     C=load->database()

      check A()

}

model2{

     C=load->database()

      check B()

}

model3{

     C=load->database()

      insert A()

}

 

## 원하는 결과 

ccontroller 1에서 A,B의 예약중 A의 예약을 다 처리 한 뒤에 B의 예약을 처리하였으면 좋겠습니다.

 

##해본거##

여기서 제가 해본것으로는 controller 1의 시작점에 

$this->C->query('LOCK TABLE ....');을 사용하고 종단점에 $this->C->query('unlock tables');를

사용하였는데 model1에서 생성된 db의 connection과 충돌하여 진행되지 않았습니다.

 

##궁금한점

controller 1에서 커넥션을 만든 후 해당 커넥션을 model1의 매개변수로 넘겨주고 그 커넥션을 다시 받아와서 컨트롤러의 마지막에 $this->C->query('unlock tables')을 하는 방법 밖에 없는 건가요?

 

많이 부족하지만 도움주시면 감사하겠습니다..

 

 다음글 CI4 MSSQL 사용하는 게 좋을까요? (5)
 이전글 세션 종료 문제 (2)

댓글

PureAni / 2020/11/26 08:51:03 / 추천 1

A와 B가 사람인건가요?

프로세스 로직인건가요?

Wally / 2020/11/26 09:27:25 / 추천 0

PureAni // A 와 B는 사람입니다^^

동시에 예약을 등록하고

동시에 ccontroller 1에 접근하여 프로세스를 처리합니다

한대승(불의회상) / 2020/11/26 11:08:18 / 추천 0
동시성문제는 DB에 맡기시고 트랜젹션으로 처리하세요.
PureAni / 2020/11/26 13:17:02 / 추천 0

DB상의 처리를 하나의 Query로 작성이 가능하다면 하나로 작성하세요.

하나의 쿼리가 불가능하고 바로바로 처리가 되어야하는게 아니라면, 중계 테이블을 하나 두세요.

A라는 사람과 B라는 사람이 동시에 입력을 넣는다면, 중계 테이블 C에 저장하고, 그 C를 Cron이 돌면서 순차적으로 처리하시면 됩니다.

(C에 저장될때는 DB 프로그램이 판단해서 우선순위를 지정해줄겁니다.)

만약에 동시에 바로바로 처리가 되어야하는 프로세스라면, 설계 및 기획을 변경을 하시고, 변경이 불가능하시다면 트랜잭션으로 최대한 처리하도록 해보셔야합니다.

한대승(불의회상) / 2020/11/26 14:11:39 / 추천 0

동시성 문제는 질문하신것처럼 발생하지 않습니다.

문제 자체를 이상하게 정의하고 테스트를 하고 있다는게 문제죠.

ccontroller 1{

     model1->check A()
     model2->check B()

     model3->insert A()
     model3->insert B()


}

이런 형태로 호출한다면 동시성 문제가 발생할 수가 없습니다.
lock table을 호출한것이 오히려 문제를 만든거죠.

다시 한번 말씀드리지만 동시성 문제는 DB에 맡기시고 트랜잭션으로 처리하세요.

Wally / 2020/11/26 17:02:32 / 추천 0

PureAni// 감사합니다 ! 가능하면 하나의 쿼리로 작성할수있도록 수정해보겠습니다 !

 

한대승(불의회상)// 답변감사합니다!

1.혹시 제가 생각한 실행순서가 동시성과는 다른 문제인걸까요 확인 부탁드려도 될까요?

 1-1 제가 바라는 실행순서는 
 A와 B가 동시에 예약 등록을 함-> A의 예약 처리시작-> check A() 통과 -> check B() 통과 -> insert A()로 A 의 예약등록완료 -> B의 예약 처리 시작 -> 그러나 이미 등록된 A의 예약때문에 check A()에서 처리불가
 
 1-2실제로 일어나는 실행순서는
 A와 B가 동시에 예약 등록을 함-> A의 예약 처리시작-> check A() 통과 -> check B() 통과 -> insert A()로 A 의 예약등록완료 -> B의 예약 처리 시작 -> check A() 통과 -> check B() 통과 -> insert A()-> insert A()로 B의 예약등록완료 
 
-해당 테이블에서 PK는 가지고 있지 않습니다.

 

2.만약에 불의회상님 말처럼 트랜잭션 처리를 하게되면 트랜잭션의 시작과 종료 위치가 

ccontroller 1{

    transaction start

     model1->check A()
     model2->check B()

     model3->insert A()
     model3->insert B()

     transaction end 
}

위와 같이 되는건가요?

한대승(불의회상) / 2020/11/26 17:30:44 / 추천 0
프로그램은 
controller 1{

    transction start;
    
     model->check()

     model->insert()

    transction end;
}

 

이렇게 작성하겠죠. ^^

중복이 되어 insert가 안된다면 트랜잭션이 이전 상태로 돌려놓을겁니다.

지금 테스트를 이상하게 하고 있는거에요.

Wally / 2020/11/26 17:53:49 / 추천 0

한대승(불의회상) // 답변 감사합니다^^

제가 아무래도 테이블을 잘못 작성한것 같습니다..

1.테이블 자체에 중복이 허용 가능한 구조라 rollback이 되지 않을것 같습니다..

 

테이블 구조부터 다시 생각한 뒤 말씀해주신대로 한번 작성해보겠습니다 .

좋은 답변 감사합니다^^

QIO™ / 2020/11/26 19:47:42 / 추천 0

SELECT문에 FOR UPDATE 구문을 사용하는 방법도 있습니다.

Wally / 2020/11/27 09:18:34 / 추천 0

QIO// 답변감사합니다 ! 

 

도움 주신대로 

임시테이블에 임시 행을 추가후 

SELECT FOR UPDATE 구문을 이용하여 락을 걸어서 제어할 생각입니다

선배님들 감사합니다 ^^