Redis分布式锁实战
Redis分布式锁实战
引言
多服务器部署项目时,多个服务实例同时操作同一资源,会出现并发争抢问题。Redis分布式锁可以保证同一时间只有一个请求执行临界代码,常用于订单扣库存、定时任务防重复执行场景。
实现原理
利用RedisSET key value NX EX命令:NX仅当key不存在才设置,EX设置过期时间。原子命令可以防止锁成功后服务宕机导致死锁。解锁时需要校验锁的值,防止误删除别人的锁。
PHP代码示例
<?php
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$lockKey = 'order:lock:1001';
$lockVal = uniqid();
// 获取锁,过期10秒
$ok = $redis->set($lockKey,$lockVal,['NX','EX'=>10]);
if($ok){
try{
// 临界区业务代码
echo "获取锁,执行业务";
}finally{
// lua脚本原子解锁,判断value一致才删除
$lua = 'if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end';
$redis->eval($lua,[$lockKey,$lockVal],1);
}
}else{
echo "获取锁失败,资源被占用";
}
注意事项
- 锁必须设置过期时间,防止程序崩溃死锁;
- 解锁必须用Lua脚本,保证判断和删除原子操作;
- 业务执行时间不能超过锁过期时间,可增加锁续期逻辑;
- 单机Redis存在单点故障,高可用场景用Redis集群或Redlock。
总结
Redis分布式锁简单易用,适合中小型Web项目并发控制。理解原子操作、锁过期、安全解锁三个关键点,避免网上简易版本带来的并发漏洞。
MySQL索引设计原则
MySQL索引设计原则
引言
MySQL索引相当于书籍目录,快速定位数据,避免全表扫描。不合理的索引不仅无法提升查询速度,还会降低写入性能。索引设计是数据库优化最基础、最高效的手段,建站、接口开发都需要掌握。
索引核心原理
InnoDB引擎索引基于B+树实现,主键索引叶子节点存储完整行数据;二级索引叶子节点存储主键值,查询会触发回表。索引字段越大,占用磁盘越多,内存缓存能存放的索引越少,查询越慢。
索引设计核心原则
- 选择性优先:优先给区分度高的字段建索引,如手机号、ID;性别、状态这类只有少量枚举值字段不适合单独建索引。
- 联合索引遵循最左匹配原则,字段顺序:等值查询在前,范围查询放后面。
- 避免在索引字段做函数运算,
where YEAR(create_time)=2026会直接失效索引。 - 不要过度建索引,每次新增、更新、删除数据,所有索引都需要同步更新,拖累写入。
示例SQL
-- 联合索引示例,适合 where uid=100 and create_time>xxx
CREATE INDEX idx_uid_ct ON user(uid,create_time);
-- 查看sql是否命中索引
EXPLAIN SELECT * FROM user WHERE uid=100;
常见踩坑
- 字符串字段不加引号,隐式类型转换,索引失效;
- 模糊查询
%关键词,前置百分号不走索引; - 联合索引跳过左侧字段,无法触发索引。
总结
索引不是越多越好,按需创建。建索引前先用explain分析执行计划,优先优化高频查询SQL,控制索引数量,平衡查询与写入性能。
PHP trait复用代码方案
PHP trait复用代码方案
引言
在PHP面向对象开发中,类只支持单继承,一个子类只能继承一个父类。当多个不同类需要共用一段逻辑,又不想强行继承同一父类时,Trait特性就是最佳解决方案。Trait可以把可复用的方法抽离出来,在多个类中引入,打破单继承限制,广泛用于项目公共方法封装。
Trait基础原理
Trait本质不是类,不能实例化,仅用于封装方法。使用use关键字在类内部引入,引入后,类可以直接调用Trait内定义的方法。
优先级规则:本类方法 > trait方法 > 父类方法。当方法重名时,优先执行当前类定义的代码。
代码示例
<?php
trait LogTrait {
public function writeLog(string $msg) {
$log = date('Y-m-d H:i:s') . " : " . $msg . PHP_EOL;
file_put_contents('./run.log', $log, FILE_APPEND);
}
}
class UserService {
use LogTrait;
public function addUser() {
$this->writeLog("新增用户数据");
}
}
$user = new UserService();
$user->addUser();
?>
多Trait冲突处理
一个类可以同时use多个Trait。多个Trait存在同名方法会直接报错,这时使用insteadof指定优先使用哪个Trait的方法,as可以给方法起别名。
trait A{ public function test(){echo "A";}}
trait B{ public function test(){echo "B";}}
class Demo{
use A,B{
A::test insteadof B;
B::test as bTest;
}
}
适用场景与坑点
✅ 适用场景:多类共用日志、验证码、文件上传等公共逻辑
⚠️ 注意:Trait不能定义静态常量;尽量不要在Trait写大量业务逻辑,只放通用工具方法,避免代码难以维护。
总结
Trait弥补了PHP单继承短板,适合项目中抽取通用能力。合理使用可以减少大量重复代码,但不能滥用,否则会造成代码逻辑分散,增加后期维护成本。
JavaScript 全屏API使用最佳实践(附代码示例)
JavaScript的生态非常丰富,但全屏API使用依然是最常用的功能点之一。本文整理了最实用的几种实现方式。
Python 爬虫获取网页标题进阶技巧分享(完整版)
很多初学者在学习Python时,都会遇到爬虫获取网页标题相关的问题。网上的资料零散且质量参差不齐,本文尝试用一篇文章把爬虫获取网页标题讲清楚。
Java 工厂模式入门核心用法解析(附代码示例)
很多初学者在学习Java时,都会遇到工厂模式入门相关的问题。网上的资料零散且质量参差不齐,本文尝试用一篇文章把工厂模式入门讲清楚。
Java StringBuilder的使用核心用法解析(建议收藏)
最近在项目里又遇到了StringBuilder的使用的典型问题,索性把解决方法整理成这篇文章,希望能帮到遇到同样问题的同学。
JavaScript 判断元素进入可视区避坑指南
面试中经常被问到的判断元素进入可视区,你真的掌握了吗?本文结合实例,讲解JavaScript中判断元素进入可视区的正确用法。
JavaScript 定时器的注意事项案例讲解
很多初学者在学习JavaScript时,都会遇到定时器的注意事项相关的问题。网上的资料零散且质量参差不齐,本文尝试用一篇文章把定时器的注意事项讲清楚。