LockService.php 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. <?php
  2. namespace crmeb\services;
  3. use think\facade\Cache;
  4. class LockService
  5. {
  6. /**
  7. * @param $key
  8. * @param $fn
  9. * @param int $ex
  10. * @return mixed
  11. * @author 吴汐
  12. * @email 442384644@qq.com
  13. * @date 2023/03/01
  14. */
  15. public function exec($key, $fn, int $ex = 6)
  16. {
  17. try {
  18. $this->lock($key, $key, $ex);
  19. return $fn();
  20. } finally {
  21. $this->unlock($key, $key);
  22. }
  23. }
  24. public function tryLock($key, $value = '1', $ex = 6)
  25. {
  26. return Cache::store('redis')->handler()->set('lock_' . $key, $value, ["NX", "EX" => $ex]);
  27. }
  28. public function lock($key, $value = '1', $ex = 6)
  29. {
  30. if ($this->tryLock($key, $value, $ex)) {
  31. return true;
  32. }
  33. usleep(200);
  34. $this->lock($key, $value, $ex);
  35. }
  36. public function unlock($key, $value = '1')
  37. {
  38. $script = <<< EOF
  39. if (redis.call("get", "lock_" .. KEYS[1]) == ARGV[1]) then
  40. return redis.call("del", "lock_" .. KEYS[1])
  41. else
  42. return 0
  43. end
  44. EOF;
  45. return Cache::store('redis')->handler()->eval($script, [$key, $value], 1) > 0;
  46. }
  47. }