Heim >Backend-Entwicklung >PHP-Tutorial >So verhindern Sie gleichzeitiges wiederholtes Schreiben in PHP

So verhindern Sie gleichzeitiges wiederholtes Schreiben in PHP

php中世界最好的语言
php中世界最好的语言Original
2018-05-17 10:17:156738Durchsuche

Dieses Mal zeige ich Ihnen, wie PHP das gleichzeitige wiederholte Schreiben verhindert. Was sind die Vorsichtsmaßnahmen für PHP, um das gleichzeitige wiederholte Schreiben zu verhindern?

1. Schreiben Sie vorne:

Im gesamten Lieferkettensystem gibt es viele Arten von Dokumenten (Bestellung, Lagerauftrag, Ankunftsauftrag, Frachtbrief, usw. usw.), wenn es um die Schnittstelle zum Schreiben von Dokumentdaten (Hinzufügungs-, Lösch- und Änderungsvorgänge) geht, kann es aufgrund des Netzwerks auch bei entsprechenden Einschränkungen durch das Frontend immer noch zu gleichzeitigen wiederholten Aufrufen kommen oder abnormale Vorgänge, die zur gleichen Verarbeitung desselben Dokuments führen;

Um zu verhindern, dass diese Situation abnormale Auswirkungen auf das System hat, haben wir eine einfache Dokumentsperre über Redis implementiert Vor der Ausführung der Geschäftslogik wird die Sperre freigegeben, nachdem die Ausführung abgeschlossen ist. Nur eine Anforderung für gleichzeitige wiederholte Vorgangsanforderungen kann die Sperre erhalten (basierend auf dem einzelnen Thread von Redis), was ein pessimistisches Sperrdesign ist 🎜>

Hinweis: Redis-Sperren werden im Allgemeinen nur zum Lösen gleichzeitiger Wiederholungen in unserem System verwendet. Bei Anfragen wird bei nicht gleichzeitigen wiederholten Anfragen normalerweise der Status der Daten in der Datenbank oder im Protokoll überprüft Der beiden Mechanismen können die Zuverlässigkeit der gesamten Verbindung gewährleisten.

2. Sperrmechanismus:

Verlässt sich hauptsächlich auf die Setnx-Befehlsimplementierung von Redis:

Aber die Verwendung von setnx hat Ein Problem besteht darin, dass die Setnx-Anweisung das Festlegen der Ablaufzeit nicht unterstützt. Sie müssen die Expire-Anweisung verwenden, um eine Zeitüberschreitung für den Schlüssel festzulegen. Auf diese Weise ist der gesamte Sperrvorgang keine atomare Operation Die Sperre ist erfolgreich, aber das Programm schlägt aufgrund eines abnormalen Beendens fehl. Das erfolgreiche Festlegen des Zeitlimits kann zu einem Deadlock führen, wenn es nicht rechtzeitig entsperrt wird (auch wenn im Geschäftsszenario kein Deadlock auftritt, ist dies kein gutes Design für nutzlose Schlüssel). bleiben im Speicher);

Diese Situation kann mithilfe von Redis-Transaktionen gelöst werden, und die beiden Anweisungen setnx und expire werden als atomare Operation ausgeführt, was jedoch in Versionen nach Redis 2.6.12 relativ problematisch sein wird , die Redis-Set-Anweisung unterstützt den NX- und Ex-Modus und unterstützt das atomare Festlegen der Ablaufzeit:

3. Sperrimplementierung (der vollständige Testcode wird unter veröffentlicht Ende):

 /**
  * 加单据锁
  * @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, [&#39;nx&#39;, &#39;ex&#39;=>$intExpireTime]);
  //加锁成功返回锁ID,加锁失败返回false
  return $bolRes ? $intUniqueLockId : $bolRes;
 }

4. Entriegelungsmechanismus:

Wenn der Vergleich erfolgreich ist, wird der Schlüssel verglichen Es ist zu beachten, dass beim Entsperren des gesamten Prozesses auch die Atomizität sichergestellt werden muss, die auf der Überwachungs- und Transaktionsimplementierung von Redis beruht Wenn einer der Schlüssel geändert (oder gelöscht) wird, wird die nachfolgende Transaktion nicht ausgeführt. Die Überwachung wird bis zum EXEC-Befehl fortgesetzt (Befehle in der Transaktion werden nach EXEC ausgeführt, sodass der Schlüsselwert der WATCH-Überwachung nach dem MULTI-Befehl geändert werden kann)

5. Entsperren der Implementierung (Schließen Sie ab Der Testcode wird am Ende veröffentlicht):

/**
  * 解单据锁
  * @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. Anbei ist der gesamte Testcode (dieser Code ist nur eine einfache Version)

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,解锁失败

Ich glaube, Sie haben den Fall in diesem Artikel gelesen. Sie beherrschen die Methode. Weitere spannende Informationen finden Sie in anderen verwandten Artikeln auf der chinesischen PHP-Website! Empfohlene Lektüre:

Detaillierte Erläuterung der Schritte zum Einrichten der Web-Cluster-Sitzungssynchronisierung in PHP

Detaillierte Erläuterung von die Schritte zum Ausschneiden und Zusammenführen großer Dateien in PHP

Das obige ist der detaillierte Inhalt vonSo verhindern Sie gleichzeitiges wiederholtes Schreiben in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn