锁(Lock),在并发处理,防止冲突的场景非常常用。

在 imi 中,你可以使用注解,或者自己实例化Lock类来实现加锁处理。

目前 imi 中仅内置支持 RedisLock,它支持分布式,当然你也可以实现Imi\Lock\Handler\ILockHandler接口,来实现其他方式的锁。

实例化使用

顺序用法

  1. $redisLock = new \Imi\Lock\Handler\Redis('锁ID', [
  2. 'poolName' => 'redis', // Redis 连接池名称,默认取redis.default配置
  3. 'db' => 1, // Redis 几号库,默认0
  4. 'waitSleepTime' => 20, // 获得锁每次尝试间隔,单位:毫秒
  5. 'keyPrefix' => 'imi:lock:', // Redis key 前置
  6. ]);
  7. if($redisLock->lock())
  8. {
  9. // 加锁后的处理
  10. // 解锁
  11. $redisLock->unlock();
  12. }
  13. else
  14. {
  15. // 加锁失败的处理
  16. }

回调用法

  1. $redisLock = new \Imi\Lock\Handler\Redis('锁ID', [
  2. 'poolName' => 'redis', // Redis 连接池名称,默认取redis.default配置
  3. 'db' => 1, // Redis 几号库,默认0
  4. 'waitSleepTime' => 20, // 获得锁每次尝试间隔,单位:毫秒
  5. 'keyPrefix' => 'imi:lock:', // Redis key 前置
  6. ]);
  7. // 执行后自动解锁
  8. $result = $redisLock->lock(function(){
  9. // 执行任务
  10. }, function(){
  11. // return 非null则不执行任务
  12. // 一般用于防止缓存击穿
  13. });
  14. if($result)
  15. {
  16. // 加锁并执行成功
  17. }
  18. else
  19. {
  20. // 加锁失败
  21. }

注解使用

@Lockable

支持参数:

  1. /**
  2. * 锁ID
  3. * 支持{id}、{data.name}形式,代入参数
  4. * 如果为null,则使用类名+方法名+全部参数,序列化后hash
  5. *
  6. * @var string|null
  7. */
  8. public $id;
  9. /**
  10. * 锁类型,如:RedisLock
  11. * 为null则使用默认锁类型(@currentServer.lock.defaultType)
  12. *
  13. * @var string|null
  14. */
  15. public $type;
  16. /**
  17. * 等待锁超时时间,单位:毫秒,0为不限制
  18. *
  19. * @var int
  20. */
  21. public $waitTimeout = 3000;
  22. /**
  23. * 锁超时时间,单位:毫秒
  24. *
  25. * @var int
  26. */
  27. public $lockExpire = 3000;
  28. /**
  29. * 锁初始化参数
  30. *
  31. * @var array
  32. */
  33. public $options = [];
  34. /**
  35. * 当获得锁后执行的回调。该回调返回非 null 则不执行加锁后的方法,本回调的返回值将作为返回值
  36. * 一般用于防止缓存击穿,获得锁后再做一次检测
  37. * 如果为{"$this", "methodName"}格式,$this将会被替换为当前类,方法必须为 public 或 protected
  38. *
  39. * @var callable
  40. */
  41. public $afterLock;

用法示例

最简单的锁:

只指定id,其它全部默认值

  1. @Lockable(id="锁ID")

定义执行任务前的操作:

  1. class Test
  2. {
  3. /**
  4. * @Lockable(id="锁ID", afterLock={"$this", "check"})
  5. */
  6. public function index()
  7. {
  8. return 1;
  9. }
  10. protected function check()
  11. {
  12. return 2;
  13. }
  14. /**
  15. * @Lockable(id="锁ID", afterLock={"$this", "check"})
  16. */
  17. public function index2()
  18. {
  19. return 3;
  20. }
  21. protected function check2()
  22. {
  23. }
  24. }
  25. $result = App::getBean('Test')->index();
  26. echo $result, PHP_EOL; // 2
  27. $result = App::getBean('Test')->index2();
  28. echo $result, PHP_EOL; // 3