PHP 는 Redis 증빙 자 물 쇠 를 실현 하고 중복 기록 을 방지 합 니 다.
전체 공급 체인 시스템 에서 여러 가지 증빙 서류(구 매 서,입고 서,화물 송장,운송장 등)가 있 을 것 이다.증빙 서 류 를 작성 하 는 데이터 와 관련 된 인터페이스(첨삭 조작)는 전단 에 관련 제한 을 하 더 라 도 네트워크 나 이상 조작 으로 인해 중복 호출 되 는 상황 이 발생 하여 같은 증빙 서 류 를 똑 같이 처리 할 수 있다.
이러한 상황 이 시스템 에 이상 한 영향 을 미 치 는 것 을 방지 하기 위해 우 리 는 Redis 를 통 해 간단 한 증빙 자 물 쇠 를 실현 했다.모든 요청 은 먼저 자 물 쇠 를 가 져 와 야 업무 논 리 를 수행 할 수 있 고 실행 이 끝 난 후에 야 자 물 쇠 를 풀 수 있다.같은 증빙서류 의 동시 반복 작업 요청 이 하나의 요청 만 잠 금(Redis 에 의존 하 는 단일 스 레 드)을 얻 을 수 있 도록 하 는 비관 적 인 잠 금 디자인 입 니 다.
주:Redis 는 우리 시스템 에 잠 겨 있 습 니 다.보통 중복 요청 을 해결 하 는 데 만 사 용 됩 니 다.동시 다발 적 이지 않 은 중복 요청 에 대해 데이터 베이스 나 로그 로 데 이 터 를 검사 하 는 상 태 를 확인 합 니 다.두 가지 체 제 를 결합 해 야 전체 링크 의 신뢰성 을 확보 할 수 있 습 니 다.
2.잠 금 메커니즘:
주로 Redis setnx 명령 에 의존 하여 이 루어 집 니 다.
그러나 setnx 를 사용 하 는 데 문제 가 있 습 니 다.즉,setnx 명령 은 만 료 시간 을 설정 하 는 것 을 지원 하지 않 습 니 다.expire 명령 을 사용 해 야 합 니 다.다른 행위 key 설정 시간 초과 시간 을 설정 해 야 합 니 다.그러면 전체 잠 금 작업 은 원자 작업 이 아니 라 setnx 잠 금 추가 성공 이 있 을 수 있 습 니 다.그러나 프로그램 이 이상 하 게 종료 되 어 시간 초과 시간 을 설정 하지 못 했 습 니 다.제때에 잠 금 을 풀 지 않 은 상황 에서잠 금 이 걸 릴 수 있 습 니 다.
이러한 상황 은 Redis 사 무 를 사용 하여 해결 할 수 있 습 니 다.setnx 와 expire 두 가지 명령 을 원자 적 인 조작 으로 실행 할 수 있 습 니 다.그러나 이렇게 하면 상대 적 으로 번 거 로 울 수 있 습 니 다.예 를 들 어 Redis 2.6.12 이후 버 전에 서 Redis set 명령 은 nx,ex 모드 를 지원 하고 원자 화 된 기한 이 지난 시간 을 설정 할 수 있 습 니 다.
3.잠 금 실현(전체 테스트 코드 는 마지막 에 붙 입 니 다):
/**
*
* @param int $intOrderId ID
* @param int $intExpireTime ( )
* @return bool|int ID, false
*/
public static function addLock($intOrderId, $intExpireTime = self::REDIS_LOCK_DEFAULT_EXPIRE_TIME)
{
//
if (empty($intOrderId) || $intExpireTime <= 0) {
return false;
}
// Redis
$objRedisConn = self::getRedisConn();
// ID, ID
$intUniqueLockId = self::generateUniqueLockId();
// , ID, Redis key( , ID )
$strKey = sprintf(self::REDIS_LOCK_KEY_TEMPLATE, $intOrderId);
// ( Redis setnx , Redis 2.6.12 , set setnx, )
$bolRes = $objRedisConn->set($strKey, $intUniqueLockId, ['nx', 'ex'=>$intExpireTime]);
// ID, false
return $bolRes ? $intUniqueLockId : $bolRes;
}
4.잠 금 해제 메커니즘:잠 금 해제 란 잠 금 을 추가 할 때 유일한 lock id 보다 성공 하면 key 를 삭제 합 니 다.주의해 야 할 것 은 잠 금 해제 전체 과정 에서 원자 성 을 확보 해 야 한 다 는 것 이다.여 기 는 redis 의 watch 와 업무 실현 에 의존 해 야 한다.
WATCH 명령 은 한 개 이상 의 키 를 감시 할 수 있 으 며,한 개의 키 가 수정 되 거나 삭제 되면 이후 의 업 무 는 실행 되 지 않 습 니 다.EXEC 명령 까지 모니터링(트 랜 잭 션 의 명령 은 EXEC 이후 에 실행 되 기 때문에 MULTI 명령 후 WATCH 모니터링 키 를 수정 할 수 있 습 니 다)
5.잠 금 해제 실현(전체 테스트 코드 는 마지막 에 붙 여 집 니 다):
/**
*
* @param int $intOrderId ID
* @param int $intLockId ID
* @return bool
*/
public static function releaseLock($intOrderId, $intLockId)
{
//
if (empty($intOrderId) || empty($intLockId)) {
return false;
}
// Redis
$objRedisConn = self::getRedisConn();
// Redis key
$strKey = sprintf(self::REDIS_LOCK_KEY_TEMPLATE, $intOrderId);
// Redis key 【 lock id】 【 】 , ,
$objRedisConn->watch($strKey);
if ($intLockId == $objRedisConn->get($strKey)) {
$objRedisConn->multi()->del($strKey)->exec();
return true;
}
$objRedisConn->unwatch();
return false;
}
6.전체 테스트 코드 를 첨부 합 니 다.
<?php
/**
* Class Lock_Service
*/
class Lock_Service
{
/**
* redis key
*/
const REDIS_LOCK_KEY_TEMPLATE = 'order_lock_%s';
/**
* ( )
*/
const REDIS_LOCK_DEFAULT_EXPIRE_TIME = 86400;
/**
*
* @param int $intOrderId ID
* @param int $intExpireTime ( )
* @return bool|int ID, false
*/
public static function addLock($intOrderId, $intExpireTime = self::REDIS_LOCK_DEFAULT_EXPIRE_TIME)
{
//
if (empty($intOrderId) || $intExpireTime <= 0) {
return false;
}
// Redis
$objRedisConn = self::getRedisConn();
// ID, ID
$intUniqueLockId = self::generateUniqueLockId();
// , ID, Redis key( , ID )
$strKey = sprintf(self::REDIS_LOCK_KEY_TEMPLATE, $intOrderId);
// ( Redis setnx , Redis 2.6.12 , set setnx, )
$bolRes = $objRedisConn->set($strKey, $intUniqueLockId, ['nx', 'ex'=>$intExpireTime]);
// ID, false
return $bolRes ? $intUniqueLockId : $bolRes;
}
/**
*
* @param int $intOrderId ID
* @param int $intLockId ID
* @return bool
*/
public static function releaseLock($intOrderId, $intLockId)
{
//
if (empty($intOrderId) || empty($intLockId)) {
return false;
}
// Redis
$objRedisConn = self::getRedisConn();
// Redis key
$strKey = sprintf(self::REDIS_LOCK_KEY_TEMPLATE, $intOrderId);
// Redis key 【 lock id】 【 】 , ,
$objRedisConn->watch($strKey);
if ($intLockId == $objRedisConn->get($strKey)) {
$objRedisConn->multi()->del($strKey)->exec();
return true;
}
$objRedisConn->unwatch();
return false;
}
/**
* Redis :IP
*/
const REDIS_CONFIG_HOST = '127.0.0.1';
/**
* Redis :
*/
const REDIS_CONFIG_PORT = 6379;
/**
* Redis ( , )
* @param string $strIp IP
* @param int $intPort
* @return object Redis
*/
public static function getRedisConn($strIp = self::REDIS_CONFIG_HOST, $intPort = self::REDIS_CONFIG_PORT)
{
$objRedis = new Redis();
$objRedis->connect($strIp, $intPort);
return $objRedis;
}
/**
* ID redis key
*/
const REDIS_LOCK_UNIQUE_ID_KEY = 'lock_unique_id';
/**
* ID( Redis incr , 、 、 、 、 , ID)
* @return mixed
*/
public static function generateUniqueLockId()
{
return self::getRedisConn()->incr(self::REDIS_LOCK_UNIQUE_ID_KEY);
}
}
//test
$res1 = Lock_Service::addLock('666666');
var_dump($res1);// lock id,
$res2 = Lock_Service::addLock('666666');
var_dump($res2);//false,
$res3 = Lock_Service::releaseLock('666666', $res1);
var_dump($res3);//true,
$res4 = Lock_Service::releaseLock('666666', $res1);
var_dump($res4);//false,
이상 이 바로 이번에 여러분 께 정리 해 드 린 모든 내용 입 니 다.저희 에 대한 성원 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
laravel에 yo에서 angularJs&coffeescript를 사용할 수 있도록 한다.먼저 yo 명령을 사용할 수 있어야하므로 아래에서 설치 global에 설치한 곳에서 laravel의 프로젝트 루트로 이동. 클라이언트 코드를 관리하는 디렉토리를 만들고 이동합니다. 클라이언트 환경 만들기 이것으로 히...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.