PHP와 MySQL은 동시 요청을 어떻게 처리합니까?
<p>PHP/Symfony가 동시 요청을 처리하는 방법이나 데이터베이스에서 잠재적인 동시 쿼리를 처리하는 방법에 대해 뭔가 빠진 것 같습니다...</p>
<p>이 코드는 불가능한 작업을 수행하는 것 같습니다. 무작위로(약 한 달에 한 번) 하단에 새 엔터티의 복사본을 생성합니다. 내 결론은 두 클라이언트가 동일한 요청을 두 번 만들고 두 스레드가 동시에 SELECT 쿼리를 실행할 때 stop == NULL로 항목을 선택한 다음 둘 다(?) 해당 항목의 중지 시간을 설정한다는 것입니다. 이런 일이 발생하면 둘 다 새 항목을 작성해야 합니다.</p>
<p>내가 아는 한 이것은 나의 논리적 개요입니다. </p>
<올>
<li>중지 시간이 NULL인 모든 항목을 가져옵니다</li>
<li>항목을 반복합니다</li>
<li>입력 날짜(UTC)가 현재 날짜(UTC)와 다른 경우에만 계속합니다</li>
<li>열린 항목의 중지 시간을 23:59:59로 설정하고 데이터베이스로 플러시합니다</li>
<li>다음날 00:00:00에 시작하는 새 항목을 작성합니다</li>
<li>이 위치에 열려 있는 다른 항목이 없는지 확인</li>
<li>이 위치에 향후 항목이 없는지 확인</li>
<li>이것만 - 새 항목을 데이터베이스에 플러시합니다</li>
</ol>
<p>컨트롤러가 자동으로 꺼졌다가 켜집니다</p>
<pre class="brush:php;toolbar:false;">//입력이 새벽(자정)에 걸쳐 있는 경우 해당 항목을 닫고 다음 날 초에 새 항목을 엽니다.
개인 함수 autocloseAndOpen($units) {
$now = new DateTime("현재", new DateTimeZone("UTC"));
$repository = $this->em->getRepository('AppEntityPoslogEntry');
$query = $repository->createQueryBuilder('e')
->where('e.stop은 NULL입니다')
->getQuery();
$results = $query->getResult();
if (!isset($results[0])) {
return null; //열린 항목이 전혀 없습니다.
}$em = $this->em;
$메시지 = "";
foreach($결과는 $r로 표시됨) {
if ($r->getPosition()->getACRGroup() == $unit) { //사용자 자신의 항목만 터치합니다.
$start = $r->getStart();
//datebreak에 걸쳐 항목을 주장합니다.
$startStr = $start->format("Y-m-d"); //비교에 필요합니다. $start->format("Y-m-d")이 비교 절에 있으면 PHP는 서식의 출력이 아니라 서식이 지정된 날짜/시간 개체를 계속 비교합니다.
$nowStr = $now->format("Y-m-d"); //비교에 필요합니다. $start->format("Y-m-d")이 비교 절에 있으면 PHP는 서식의 출력이 아닌 서식이 지정된 날짜/시간 개체를 계속 비교합니다.
if ($startStr < $nowStr) {
$stop = new DateTimeImmutable($start->format("Y-m-d")."23:59:59", new DateTimeZone("UTC"));
$r->setStop($stop);
$em->flush();
$txt = $unit->getName() . " datebreak(UTC)에 걸쳐 위치(" . $r->getPosition()->getName() . ")에 항목이 있습니다. "에 자동으로 종료됩니다. . $stop->format("Y-m-d H:i:s") . "z.";;
$messages .= "<p>" . $txt . "</p>";
//새 항목 열기
$newStartTime = $stop->modify('+1초');
$entry = 새 항목();
$entry->setStart( $newStartTime );
$entry->setOperator( $r->getOperator() );
$entry->setPosition( $r->getPosition() );
$entry->setStudent( $r->getStudent() );
$em->지속($entry);
//새 항목을 자동 열기 전에 향후 항목이 없는지 확인
$futureE = $this->checkFutureEntries($r->getPosition(),true);
$openE = $this->checkOpenEntries($r->getPosition(), true);
if ($futureE !== 0 || $openE !== 0) {
$txt = ""에 대한 새 항목을 열려고 했습니다. . $r->getOperator()->getSignature() . " 다음 날 같은 위치(" . $r->getPosition()->getName() . ")에 있지만 충돌하는 항목이 있습니다.";
$messages .= "<p>" . $txt . "</p>";
}또 다른 {
$em->flush() //DB에 저장
$txt = "'$r->getOperator()->getSignature()'에 대한 새 항목이 같은 위치에 열렸습니다(" . $r->getPosition()-> getName() ")".
$messages .= "<p>" $txt .
}
}
}
}
$ 메시지를 반환합니다.
}</pre>
<p>여기서는 checkOpenEntries()를 사용하여 현재 해당 위치에 stoptime == NULL인 항목이 있는지 확인하기 위해 추가 검사를 실행하기도 했습니다. 처음에는 하나의 요청이 데이터베이스에서 실행되고 작동 중이면 첫 번째 요청이 완료될 때까지 다른 요청이 시작되지 않을 것이라고 생각했기 때문에 이것이 중복된다고 생각했습니다. </p>
<pre class="brush:php;toolbar:false;">비공개 함수 checkOpenEntries($position,$checkRelatives = false) {
$positionsToCheck = 배열();
if ($checkRelatives == true) {
$positionsToCheck = $position->getRelatedPositions();
$positionsToCheck[] = $위치;
} 또 다른 {
$positionsToCheck = 배열($position);
}
//위치에 대해 열려 있는 모든 항목을 가져옵니다.
$repository = $this->em->getRepository('AppEntityPoslogEntry');
$query = $repository->createQueryBuilder('e')
->where('e.stop은 NULL이고 e.position IN (:positions)')
->setParameter('positions', $positionsToCheck)
->getQuery();
$results = $query->getResult();
if(!isset($results[0])) {
return 0; //호출자에게 열린 항목이 없음을 알립니다.
} 또 다른 {
if (count($results) === 1) {
return $results[0]; //열린 항목이 정확히 하나인 경우 해당 객체를 호출자에게 반환합니다.
} 또 다른 {
$body = ' ' 위치에 대한 열린 로그 항목이 1개 이상 발견되었습니다. ' . $position->getACRGroup()->getName() ' 데이터베이스에 손상된 데이터가 있는 것 같습니다.';
$this->이메일($body);
$output['성공'] = 거짓;
$output['message'] = $body . ' 문제를 알리기 위해 ' .$this->globalParameters->get('poslog-email-to') '로 자동 이메일이 전송되었습니다. 필수입니다.';
$output['logdata'] = null;
return $this->prepareResponse($output);
}
}
}</pre>
<p>원하는 작업을 수행하려면 이 기능을 활성화하려면 일종의 "데이터베이스 잠금" 방법을 사용해야 합니까? </p>
<p>모든 기능을 테스트했으며 다양한 상태를 시뮬레이션했을 때(정지 시간에 NULL을 입력하는 등, 그렇지 않은 경우에도) 모든 것이 잘 작동했습니다. 대부분의 경우 모든 것이 잘 작동하지만 월 중순의 어느 날 이런 일이 발생합니다...</p>