Last active
September 29, 2021 06:17
-
-
Save shellus/b655a82a09a74e33e85d3c8aa4ba24be to your computer and use it in GitHub Desktop.
Laravel mysql Counter code
This file contains 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 characters
/** | |
* @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 { | |
// 不存在则创建 | |
// todo 这里没有处理两个创建冲突的情况,可以用tag的唯一索引来代替 | |
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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment