Last active
September 29, 2021 06:17
-
-
Save shellus/b655a82a09a74e33e85d3c8aa4ba24be to your computer and use it in GitHub Desktop.
Revisions
-
娃娃脾气3 revised this gist
Sep 29, 2021 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,4 @@ /** * @param $tag * @param int $num @@ -21,6 +22,7 @@ public static function incr($tag, $num = 1) if (!$counter) { try { // 不存在则创建 // todo 这里没有处理两个创建冲突的情况,可以用tag的唯一索引来代替 CounterModel::create(['tag' => $tag, 'num' => 0]); $counter = CounterModel::where('tag', $tag)->lockForUpdate()->first(); } catch (\PDOException $PDOException) { -
娃娃脾气3 created this gist
Sep 29, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,58 @@ /** * @param $tag * @param int $num * @return int|mixed */ public static function incr($tag, $num = 1) { if ($num < 1) { throw new \Exception('num err'); } // const TAG_MAX_LEN = 64; if (strlen($tag) > self::TAG_MAX_LEN) { throw new \Exception('tag too long'); } $db = CounterModel::query()->getConnection(); try { $db->beginTransaction(); $counter = CounterModel::where('tag', $tag)->lockForUpdate()->first(); if (!$counter) { try { // 不存在则创建 CounterModel::create(['tag' => $tag, 'num' => 0]); $counter = CounterModel::where('tag', $tag)->lockForUpdate()->first(); } catch (\PDOException $PDOException) { // SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction if (strpos($PDOException->getMessage(), 'Deadlock') === false) { throw $PDOException; } // 如果创建失败,就用其他事务创建的 // 等待其他事务完成创建 sleep(1); $counter = CounterModel::where('tag', $tag)->lockForUpdate()->first(); if (!$counter) { throw new \Exception('放弃创建,但还是读不到数据'); } } } if ($counter) { $counter->num = $counter->num + $num; if ($counter->num > self::NUM_MAX_MYSQL) { // const NUM_MAX_MYSQL = 255 * 255 * 255 * 255; throw new \Exception('递增达到数据库最大值'); } $counter->save(); $result = $counter->num; } $db->commit(); } catch (\Exception $exception) { $db->rollBack(); throw $exception; } return $result; }