2009-11-11 5 views
7

저는 최근에 PHP로 웹 개발 작업을 해왔습니다. 그래서 나는 일반적으로 언어에 대해 공부하게되었습니다. 지금까지는 데이터베이스와 상호 작용하는 데 사용할 필요가 없었지만 그렇게하기 위해 많은 편리한 기능을 제공합니다.PHP와 동시성

기본 SQL을 알고 데이터베이스의 기본 데이터 조작으로 작업했지만 PHP/Javascript/SQL에서 자신의 웹 사이트를 기반으로하는 웹 개발자가 어떻게 동일한 데이터를 수정하는 사용자를 관리 할 수 ​​있는지 이해하지 못합니다. 같은 시간.

예를 들어, 당신은 그들이 가입 두 팀 중 하나에 사용자를 분할 블랙 잭 웹 사이트가 있다고 가정 할 수 있습니다. 사용자가 게임에 이길 때마다 위닝의 일부가 해당 팀의 누적 합계에 추가됩니다.

... 
$total = mysql_query("SELECT score FROM team1"); 
$total = $total + $mytotal; 
mysql_query("UPDATE team1 SET score='".$total."'"); 
... 

두 선수가 동시에 재생하는 경우, 그것은 그들이 다른 전에 SELECT 호출 모두 매우 가능성 :

그래서이 이런 식으로 뭔가를 보이는 수행하는 기능에 대한 의사 코드를 말할 수 하나는 테이블을 증가시키고 업데이트 할 수있는 기회를 가지므로, 한 사용자의 변경 사항은 즉시 덮어 쓰기됩니다.

제 질문은 어떻게 이것을 피합니까? 코드 단계에서 PHP를 사용하여 완성 되었습니까? 아니면이 문제를 방지하기 위해 도움이되는 데이터베이스가 제공하는 기능이 있습니까?

나는 약간의 연구를 해왔고, PHP는 semaphore 메카니즘을 제공하고 있으며, mysql이 LOCK table feature을 제공하는 것으로 나타났습니다. 그러나, 이들 중 어느 것이 실제로 사용되는지는 확실하지 않습니다.

답변

5

실제 문제가이 간단한 예보다 큰 경우 잠금 테이블과 함께 트랜잭션을 사용하여 사용자가 서로 겹쳐 쓰지 않도록해야합니다.

+0

감사합니다 -하지만 난 더 PHP를 포함하는 더 복잡한 동시성 문제에 가장 좋은 방법이 무엇인지를 찾고 있었다 한 줄의 SQL은 적합하지 않습니다. (미안 내 예제가 오도 된 경우) –

11

로직을 DB에 보관하십시오. 의미가 대부분 당신을 위해 해결되었습니다.

update teams 
set score = score + 1 
where team_id = 1 

.. 또는 점수와 팀 번호.

1

데이터베이스는 동시 잠금을 관리하고 변경 사항이 원자 적으로 이루어 지도록합니다. 이는 ACID 트랜잭션을 지원하는 데이터베이스를 사용하는 이점입니다.

대부분의 경우 변경 사항으로 인해 잠금 경합이 최소화됩니다. 하지만 여전히 발생할 수 있으므로 SQL 쿼리를 실행 한 후에 반환 된 오류 상태를 확인해야합니다. mysql_query() 함수는 문제가 있으면 FALSE을 반환합니다.

mysql_errno()을 호출하여 원인 (업데이트 충돌, 불충분 한 사용 권한, SQL 구문 오류 등)을 파악할 수 있습니다. MySQL 오류 코드 참조는 http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html을 참조하십시오.

1

저는 Xepochs 대답에 동의합니다. 절대적으로 필요하지 않으면 동시성 문제를 일으키지 마십시오. 서로 다른 잠금 전략에 대한 훌륭한 대답은 here을 참조하십시오.

4

주요 데이터베이스는 이러한 상황을 처리하도록 설계되었습니다. MySQL을 사용하면

는 이노 스토리지 엔진에 기록되는 행 잠금 행 잠금 기능을 갖는다. 따라서 동일한 행에 대한 모든 갱신 요청은 행의 이전 조작이 완료 될 때까지 대기합니다.

MyISAM 스토리지 엔진을 사용하면 행을 업데이트 할 때 전체 테이블을 잠급니다. 여러 플레이어가 동시에 업데이트 요청을 푸시하면 서버에 초크가 생깁니다. 따라서 모든 데이터베이스와 특히이 용도로 사용하는 스토리지 엔진에 관한 것입니다.

+0

+1 구문을 잠그고있는 mysql 행은 무엇입니까? –

+0

업데이트 될 행은 InnoDB에서 자동으로 잠 깁니다. 트랜잭션에서 열을 읽을 때 행을 잠 그려면 SELECT ... FOR UPDATE 또는 SELECT ... LOCK IN SHARE 모드를 사용하십시오. 차이점은 MySQL Reference Manual의이 부분을 추천합니다. http://dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html – Nirmal

1

위의 답변 중 어느 것도 설계상의 결함에 부딪 힐 수도 있다고 생각하지 않습니다.

예 모든 대답이 정확합니다. mysql은 경주 조건과 상호 배타적 인 테이블 액세스를 처리 할 수 ​​있습니다.

그러나 이와 같은 문제가 발생하면 디자인을 다시 생각해 볼 때입니다. 왜 위닝 중 일부를 추가했는지에 대한 사용자 ID를 유지하지 않습니까? 그러면 다음 값을 가질 수 있습니다.

INSERT INTO team1(userid, amount) VALUES(32, 100); 
    SELECT SUM(amount) FROM team1 
or 
    REPLACE INTO team1 SET amount = $total 

그러나 그게 나 였으면 나는 신경 쓰지 않을 것입니다. 나는 단순히 set_cookie (team_score, team_score + amount)를 유지하고 모든 것을 클라이언트 측에서 유지한다. 점수를 읽으려는 경우 AJAX 요청을 실행하여 서버를 읽거나 쓰고 클라이언트 인터페이스를 비동기 적으로 업데이트합니다. 웹 개발이 기본이라고 지적 했으므로 이것을 달성하는 가장 쉬운 방법은 비동기 클라이언트 - 서버 통신을위한 jQuery 프레임 워크를 살펴 보는 것입니다. 편집

: 그리고 다른 플레이어가 점수에 금액을 추가 할 때 모든 사람의 UI를 업데이트하는 문제에 대한, 나는 그들이 즉시 얻을 수 있도록 선수들의 클라이언트에 잘 데이터 모델 스타킹하는 당신이 backbone.js 조사 제안 점수가 변경되면 업데이트됩니다.

0

데이터베이스에는 동시성 제어 기능이 내장되어 있습니다. 예를 들어 postgres 동시성 제어 here을 읽을 수 있습니다. 필자가 맞다면, pgsql의 기본 설정은 낙관적 인 잠금과 읽기 커밋 된 트랜잭션 격리입니다. 즉, 모든 트랜잭션은 다른 커밋되지 않은 트랜잭션에 의해 수행 된 변경을 인식합니다.

이 설정은 괜찮으므로 간단히 UPDATE team1 SET score = score + mytotal을 수행하면 데이터베이스가 동시 처리 문제를 잘 처리합니다.

더 긴 선택 업데이트 문제가있는 경우 SELECT FOR UPDATE 쿼리를 사용하여 첫 번째 선택 항목을 통해 행을 수동으로 잠글 수 있습니다.

이 현재 가장 좋은 방법은 ... 내가로부터 배우고 여러 가지 좋은 답변을 모든 사람에게