From 8938ce9cbe4bc3daf11585923e72d534c4623776 Mon Sep 17 00:00:00 2001 From: lq <13849061902@qq.com> Date: Wed, 22 May 2024 15:50:08 +0800 Subject: [PATCH] add code --- Buddha.pid | 2 +- app/config/define.php | 6 +- app/config/redis.php | 10 ++ app/config/redispool.php | 8 ++ app/controller/UserController.php | 16 ++- core/annotationhandlers/LockHandler.php | 82 +++++++++++++++ core/annotationhandlers/RedisHandler.php | 126 +++++++++++++++++++++++ core/annotations/Lock.php | 17 +++ core/annotations/Redis.php | 23 +++++ core/init/RedisHelper.php | 36 +++++++ core/lib/PHPRedisPool.php | 27 +++++ core/lib/RedisPool.php | 75 ++++++++++++++ 12 files changed, 424 insertions(+), 4 deletions(-) create mode 100644 app/config/redis.php create mode 100644 app/config/redispool.php create mode 100644 core/annotationhandlers/LockHandler.php create mode 100644 core/annotationhandlers/RedisHandler.php create mode 100644 core/annotations/Lock.php create mode 100644 core/annotations/Redis.php create mode 100644 core/init/RedisHelper.php create mode 100644 core/lib/PHPRedisPool.php create mode 100644 core/lib/RedisPool.php diff --git a/Buddha.pid b/Buddha.pid index f70d7bb..20cfbee 100644 --- a/Buddha.pid +++ b/Buddha.pid @@ -1 +1 @@ -42 \ No newline at end of file +1940 \ No newline at end of file diff --git a/app/config/define.php b/app/config/define.php index 8eb8f23..9e981cd 100644 --- a/app/config/define.php +++ b/app/config/define.php @@ -3,6 +3,8 @@ define("ROOT_PATH", dirname(dirname(__DIR__))); $GLOBAL_CONFIGS = [ - 'db' => require_once(__DIR__ . "/db.php"), - 'dbpool' => require_once(__DIR__ . '/dbpool.php'), + 'db' => require_once(__DIR__ . "/db.php"), + 'dbpool' => require_once(__DIR__ . '/dbpool.php'), + 'redis' => require_once(__DIR__ . '/redis.php'), + 'redispool' => require_once(__DIR__ . '/redispool.php'), ]; \ No newline at end of file diff --git a/app/config/redis.php b/app/config/redis.php new file mode 100644 index 0000000..9386007 --- /dev/null +++ b/app/config/redis.php @@ -0,0 +1,10 @@ + [ + 'host' => '127.0.0.1', + 'port' => '6379', + 'auth' => '', + 'db' => 6 + ], +]; \ No newline at end of file diff --git a/app/config/redispool.php b/app/config/redispool.php new file mode 100644 index 0000000..fbecf50 --- /dev/null +++ b/app/config/redispool.php @@ -0,0 +1,8 @@ + [ + "min" => 20, + "max" => 30, + "idleTime" => 40 + ] +]; \ No newline at end of file diff --git a/app/controller/UserController.php b/app/controller/UserController.php index 6544639..264be22 100644 --- a/app/controller/UserController.php +++ b/app/controller/UserController.php @@ -3,11 +3,14 @@ namespace App\controller; use App\model\User; use Core\annotations\Bean; use Core\annotations\Value; +use Core\annotations\Redis; +use Core\annotations\Lock; use Core\annotations\DB; use Core\annotations\RequestMapping; use Core\http\Request; use Core\http\Response; use Core\init\MyDB; +use Core\init\RedisHelper; use DI\Attribute\Inject; /** @@ -20,6 +23,7 @@ class UserController * @var MyDB */ private $db; + /** * @Value () */ @@ -55,10 +59,20 @@ class UserController /** * @RequestMapping(value="/user/json") + * @Redis(key="name") */ public function json() { - $user = $this->user::first(); + $user = $this->db->table('user')->get(); return ['code' => 1, 'msg' => 'success', 'data' => $user]; } + + /** + * @Lock(prefix="lock",key="#0") + * @RequestMapping(value="/user/lock/{uid:\d+}") + */ + public function lock( Request $request, $uid, Response $response) + { + return $this->db->table('user')->get(); + } } \ No newline at end of file diff --git a/core/annotationhandlers/LockHandler.php b/core/annotationhandlers/LockHandler.php new file mode 100644 index 0000000..b56cc92 --- /dev/null +++ b/core/annotationhandlers/LockHandler.php @@ -0,0 +1,82 @@ +prefix . getKey($self->key, $params), $self->expire], 1); +} + +function delLock($self, $params) +{//释放锁脚本 + $script = <<prefix . getKey($self->key, $params)], 1); +} + +function lock($self, $params) +{//争抢锁 + $retry = $self->retry; + while ($retry-- > 0) { + $get_lock = getLock($self, $params); + if ($get_lock) { + return true; + break; + } + usleep(1000 * 200); + } + return false; +} + +function run($self, $params, $func) +{//执行抢锁 + try { + if (lock($self, $params)) { + $result = call_user_func($func, ...$params);//执行业务逻辑 + delLock($self, $params); + return $result; + } + return false; + } catch (\Exception $exception) { + delLock($self, $params); + return 'false'; + } +} + +return [ + Lock::class => function (\ReflectionMethod $method, $instance, $self) { + $d_collector = BeanFactory::getBean(DecoratorCollector::class); + $key = get_class($instance) . "::" . $method->getName(); + $d_collector->dSet[$key] = function ($func) use ($self) { //收集装饰器 放入 装饰器收集类 + return function ($params) use ($func, $self) { + /** @var $self Lock */ + if ($self->key != '') { + $result = run($self, $params, $func); + if (!$result) { + return '服务器繁忙'; + } + return $result; + } + return call_user_func($func, ...$params);//执行业务逻辑 + }; + }; + return $instance; + } + +]; \ No newline at end of file diff --git a/core/annotationhandlers/RedisHandler.php b/core/annotationhandlers/RedisHandler.php new file mode 100644 index 0000000..eff524b --- /dev/null +++ b/core/annotationhandlers/RedisHandler.php @@ -0,0 +1,126 @@ +prefix . getKey($self->key, $params); //缓存key + $getFromRedis = RedisHelper::get($_key); + if ($getFromRedis) { //缓存如果有,直接返回 + return $getFromRedis; + } else { //缓存没有,则直接执行原控制器方法,并返回 + $getData = call_user_func($func, ...$params); + if ($self->expire > 0) {//过期时间 + RedisHelper::setex($_key, $self->expire, json_encode($getData)); + } else { + RedisHelper::set($_key, json_encode($getData)); + } + return $getData; + } +} + +function RedisByHash(Redis $self, array $params, $func) +{//处理hash类型的数据 + $_key = $self->prefix . getKey($self->key, $params); //缓存key + $getFromRedis = RedisHelper::hgetall($_key); + if ($getFromRedis) { //缓存如果有,直接返回 + if ($self->incr != '') { + RedisHelper::hIncrBy($_key, $self->incr, 1); + } + return $getFromRedis; + } else { //缓存没有,则直接执行原控制器方法,并返回 + $getData = call_user_func($func, ...$params); + if (is_array($getData) || is_object($getData)) { + if (is_object($getData)) {//如果是对象,转换成数组 + $getData = json_decode(json_encode($getData), 1); + } + $keys = implode("", array_keys($getData)); + if (preg_match("/^\d+$/", $keys)) { + foreach ($getData as $k => $data) { + RedisHelper::hmset($self->prefix . getKey($self->key, $data) . $k, $data); + } + } else { + RedisHelper::hmset($_key, $getData); + } + + } + return $getData; + } +} + +function RedisByScrtedSet(Redis $self, array $params, $func) +{//处理有序集合类型的数据 + if ($self->coroutine) { + $chan = call_user_func($func, ...$params); + $getData = []; + for ($i = 0; $i < $chan->capacity; $i++) { + $re = $chan->pop(5); + $getData = array_merge($getData, $re); + } + } else { + $getData = call_user_func($func, ...$params); + } + if (is_array($getData) || is_object($getData)) { + if (is_object($getData)) {//如果是对象,转换成数组 + $getData = json_decode(json_encode($getData), 1); + } + foreach ($getData as $data) { + RedisHelper::zAdd($self->prefix, $data[$self->score], $self->member . $data[$self->key]); + } + } + return $getData; +} + +function RedisByLua($self, $params, $func) +{//lua脚本 + return RedisHelper::eval($self->script); +} + +return [ + Redis::class => function (\ReflectionMethod $method, $instance, $self) { + $d_collector = BeanFactory::getBean(DecoratorCollector::class); + $key = get_class($instance) . "::" . $method->getName(); + $d_collector->dSet[$key] = function ($func) use ($self) { //收集装饰器 放入 装饰器收集类 + return function ($params) use ($func, $self) { + /** @var $self Redis */ + + if ($self->script != '') { + return RedisByLua($self, $params, $func); + } + if ($self->key != "") { //处理缓存 + switch ($self->type) { + case "string": + return RedisByString($self, $params, $func); + case "hash": + return RedisByHash($self, $params, $func); + case "sortedset": + return RedisByScrtedSet($self, $params, $func); + default: + return call_user_func($func, ...$params); + } + } + return call_user_func($func, ...$params); + }; + }; + return $instance; + } + +]; \ No newline at end of file diff --git a/core/annotations/Lock.php b/core/annotations/Lock.php new file mode 100644 index 0000000..c126283 --- /dev/null +++ b/core/annotations/Lock.php @@ -0,0 +1,17 @@ +getConnection(); + try{ + if(!$redis_obj) { + return false; + } + return $redis_obj->redis->$name(...$arguments); + }catch (\Exception $exception){ + return $exception->getMessage(); + }finally{ + if($redis_obj) + $pool->close($redis_obj); + } + } +} \ No newline at end of file diff --git a/core/lib/PHPRedisPool.php b/core/lib/PHPRedisPool.php new file mode 100644 index 0000000..ed7f5ba --- /dev/null +++ b/core/lib/PHPRedisPool.php @@ -0,0 +1,27 @@ +connect($default["host"],$default["port"]); + if($default["auth"]!=""){ + $redis->auth($default["auth"]); + } + $redis->select($default['db'] ?? 0); + return $redis; + } +} \ No newline at end of file diff --git a/core/lib/RedisPool.php b/core/lib/RedisPool.php new file mode 100644 index 0000000..7acd8ec --- /dev/null +++ b/core/lib/RedisPool.php @@ -0,0 +1,75 @@ +min = $min; + $this->max = $max; + $this->idleTime = $idleTime; + $this->conns = new \Swoole\Coroutine\Channel($this->max); + //构造方法直接初始化Redis连接 + for ($i = 0; $i < $this->min; $i++) { + $this->addRedisToPool();//统一调用 + } + } + + public function getCount() + { + return $this->count; + } + + public function getConnection() + {//取出 + if ($this->conns->isEmpty()) { + if ($this->count < $this->max) {//连接池没满 + $this->addRedisToPool(); + $getObject = $this->conns->pop(); + } else { + $getObject = $this->conns->pop(5); + } + } else { + $getObject = $this->conns->pop(); + } + if ($getObject) + $getObject->usedtime = time(); + return $getObject; + } + + public function close($conn) + {//放回连接 + if ($conn) { + $this->conns->push($conn); + } + } + + public function addRedisToPool() + { //把对象加入池 + try { + $this->count++; + $db = $this->newRedis(); + if (!$db) throw new \Exception("redis创建错误"); + $dbObject = new \stdClass(); + $dbObject->usedTime = time(); + $dbObject->redis = $db; + + $this->conns->push($dbObject); + } catch (\Exception $ex) { + $this->count--; + } + } +} \ No newline at end of file