Redis 缓存穿透解决

Redis 缓存穿透解决方案

缓存穿透是指查询一个数据库里根本不存在的数据,因为缓存里也没有,所以每次请求都打到数据库。如果有人恶意攻击,数据库可能被打挂。

什么是缓存穿透

正常流程:先查缓存,缓存有就直接返回,没有再查数据库,然后写入缓存。

如果查询的数据数据库里也没有,那缓存永远都不会命中,每次请求都会查数据库,这就是缓存穿透。

解决方案一:缓存空值

最简单的办法,数据库查不到也往缓存里写一个空值,设个短过期时间。

$data = $redis->get($key);
if ($data === null) {
    $data = $db->query($sql);
    if ($data === null) {
        // 缓存空值,60秒过期
        $redis->setex($key, 60, '');
    } else {
        $redis->setex($key, 3600, $data);
    }
}

优点:简单直接
缺点:会占用更多缓存空间,大量空值缓存会浪费内存

解决方案二:布隆过滤器

在缓存前面加一层布隆过滤器,先判断数据是否存在,不存在直接返回。

布隆过滤器的原理是用一个大的位数组和多个哈希函数,把存在的数据标记为1。查询时如果所有哈希位置都是1,说明可能存在;只要有一个位置是0,说明一定不存在。

优点:内存占用小,效率高
缺点:有一定误判率(说存在可能不存在,说不存在一定不存在)

两种方案对比

方案 优点 缺点 适用场景
缓存空值 简单 浪费内存 数据量小,穿透不严重
布隆过滤器 内存效率高 有误差 数据量大,穿透严重

总结

缓存穿透是常见的缓存问题,小项目用缓存空值就够了,大项目数据量大就上布隆过滤器。两种方案都能解决问题,根据实际场景选就行。


emer 发布于  2026-10-4 10:43 

Nginx 反向代理配置

Nginx 反向代理配置详解

Nginx 反向代理是最常用的服务器配置之一,把请求转发给后端服务。本文讲清楚核心配置。

1. 基本配置

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

2. 传递真实IP

后端服务要拿到用户真实IP,需要配置:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

3. 负载均衡

多台后端服务器,用 upstream 做负载均衡:

upstream backend {
    server 127.0.0.1:8080 weight=1;
    server 127.0.0.1:8081 weight=2;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

4. 超时设置

proxy_connect_timeout 60s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;

5. 静态文件处理

静态文件直接由 Nginx 处理,不用转发给后端:

location ~* \.(js|css|png|jpg|gif)$ {
    root /data/www;
    expires 30d;
}

6. HTTPS 反向代理

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

总结

Nginx 反向代理的核心就是 proxy_pass,配上 proxy_set_header 传递必要信息,再加上超时和静态文件处理,基本够用了。


emer 发布于  2026-10-4 10:42 

MySQL 慢查询优化技巧

MySQL 慢查询优化实战技巧

数据库慢查询是生产环境最常见的性能问题之一。掌握慢查询优化技巧,能让系统性能提升数倍。

1. 开启慢查询日志

先开启慢查询日志,找出哪些 SQL 慢:

slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log

超过1秒的查询就会被记录。

2. 用 Explain 分析

慢 SQL 拿到后,用 EXPLAIN 分析执行计划:

EXPLAIN SELECT * FROM users WHERE name = '张三';

重点看:

  • type:访问类型,ALL 是全表扫描,要优化
  • key:实际用到的索引
  • rows:扫描行数
  • Extra:额外信息,Using filesort、Using temporary 要警惕

3. 加索引

最直接的优化就是加索引:

ALTER TABLE users ADD INDEX idx_name(name);

加索引原则:

  • WHERE、JOIN、ORDER BY 字段优先
  • 区分度高的字段效果好
  • 联合索引遵循最左前缀

4. 避免 SELECT *

只查需要的字段:

-- 不好
SELECT * FROM users WHERE id = 1;

-- 好
SELECT id, name FROM users WHERE id = 1;

5. 深分页优化

LIMIT 100000, 10 很慢,因为要扫描10万行:

-- 不好
SELECT * FROM users LIMIT 100000, 10;

-- 好,用子查询
SELECT * FROM users 
WHERE id >= (SELECT id FROM users LIMIT 100000, 1)
LIMIT 10;

6. 大表拆小

单表数据量超过千万行,性能会下降。可以:

  • 按时间分表
  • 按用户ID分库
  • 归档历史数据

7. 总结

慢查询优化的核心思路:先找慢 SQL,再分析执行计划,然后加索引或改写 SQL。优化完记得对比前后效果,确保真的变快了。


emer 发布于  2026-10-4 10:41 

Linux 进程管理命令

Linux 进程管理常用命令

服务器上跑了多少进程?哪个进程占内存多?怎么杀进程?这些命令必须会。

1. 查看进程

# 查看所有进程
ps aux

# 查找指定进程
ps aux | grep nginx

# 实时查看
top

2. top 命令详解

top 是最常用的进程查看工具:

  • 第一行:系统负载
  • 第二行:任务数
  • 第三行:CPU 使用率
  • 第四行:内存使用
  • 第五行:Swap 使用

按 q 退出,按 k 杀进程。

3. 杀进程

# 按 PID 杀
kill 1234

# 强制杀
kill -9 1234

# 按名字杀
pkill nginx

# 杀掉所有同名进程
killall nginx

4. 查看端口占用

# 查看端口被谁占了
netstat -tlnp | grep 80

# 或者用 ss
ss -tlnp | grep 80

5. 查看进程树

# 查看进程父子关系
pstree

# 查看某个进程的子进程
pstree -p 1234

6. 后台运行

# 后台运行
nohup ./script.sh &

# 查看后台任务
jobs

# 把任务调到前台
fg %1

7. 查看资源占用

# 内存占用排行
ps aux --sort=-%mem | head

# CPU 占用排行
ps aux --sort=-%cpu | head

总结

日常运维就这几个命令:ps、top、kill、netstat、nohup。学会这些,服务器进程管理基本够用了。


emer 发布于  2026-10-4 10:38 

PHP 安全最佳实践

PHP 开发必须注意的安全问题

PHP 开发最容易出安全问题,几个常见坑一定要避开。

1. SQL 注入

最常见的安全漏洞。用户输入拼接到 SQL 里,被注入恶意 SQL。

解决方案:用预处理语句

// 不要这样
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];

// 要这样
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);

2. XSS 跨站脚本

用户输入直接输出到页面,被注入恶意 JS。

解决方案:输出时转义

echo htmlspecialchars($user_input);

3. CSRF 跨站请求伪造

别人伪造你的请求操作。

解决方案:加 Token 验证

// 表单里加 Token
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['token']; ?>">

// 后端验证
if ($_POST['csrf_token'] !== $_SESSION['token']) {
    die('CSRF 攻击');
}

4. 文件上传漏洞

用户上传 PHP 文件,直接拿到 webshell。

解决方案:

  • 限制文件类型
  • 重命名文件
  • 上传目录不执行 PHP

5. 密码明文存储

数据库被拖库,密码全泄露。

解决方案:用 password_hash

$hash = password_hash($password, PASSWORD_DEFAULT);

// 验证
password_verify($password, $hash);

6. 错误信息泄露

生产环境把报错直接展示给用户,暴露路径和代码。

解决方案:关闭 display_errors

display_errors = Off
log_errors = On

总结

PHP 安全的核心:用户输入都不可信,所有输出都要转义,数据库操作用预处理。安全开发意识比工具更重要。


emer 发布于  2026-10-4 10:37 

MySQL 索引原理详解

MySQL 索引为什么能提速

索引是数据库性能优化的核心,搞懂原理才能用对。

1. 为什么慢查询慢

没有索引,MySQL 就得全表扫描,一行一行找。100万行数据就得扫100万次,当然慢。

有了索引,就像书有目录,直接定位到位置,查几百万行也很快。

2. B+ 树索引

MySQL InnoDB 默认用 B+ 树做索引。

  • 树的高度低,一般3-4层
  • 一次查询只需3-4次磁盘IO
  • 叶子节点存数据,非叶子节点存索引

3. 聚簇索引 vs 二级索引

聚簇索引:数据和索引放在一起,按主键组织。一张表只有一个聚簇索引。

二级索引:索引和数据分开,叶子节点存主键值。查二级索引需要回表查主键。

4. 覆盖索引

如果查询的字段都在索引里,就不用回表了,叫覆盖索引。

-- name有索引
SELECT name FROM users WHERE name = '张三';
-- 覆盖索引,不用回表

5. 最左前缀

联合索引 (a, b, c),必须从最左列开始用:

  • WHERE a = 1 能用
  • WHERE a = 1 AND b = 2 能用
  • WHERE b = 2 用不了

6. 索引失效场景

  • 索引字段做函数运算
  • 隐式类型转换
  • like 以 % 开头
  • 联合索引不满足最左前缀

总结

索引是空间换时间。不是越多越好,太多索引会影响写入性能,占用额外存储空间。


emer 发布于  2026-10-4 10:36 

PHP 8.0 新特性

PHP 8.0 有哪些重磅更新

PHP 8.0 是一个大版本更新,带来了很多革命性的特性。

1. JIT 编译

PHP 8.0 引入了 JIT(即时编译),性能大幅提升,计算密集型场景性能翻倍。

2. 命名参数

array_filter(array: $array, callback: fn($x) => $x > 0);

不用按顺序传参,写参数名就行,可读性更好。

3. 枚举 Enum

enum Status: string
{
    case Pending = 'pending';
    case Active = 'active';
    case Rejected = 'rejected';
}

4. 构造函数属性提升

class User {
    public function __construct(
        public int $id,
        public string $name
    ) {}
}

不用再写 $this->id = $id 了,构造函数直接定义属性。

5. 空安全运算符

$user?->getAddress()?->city;

不用层层判断 null,有 null 直接返回 null。

6. Match 表达式

$result = match($status) {
    200 => '成功',
    404 => '未找到',
    default => '未知'
};

比 switch 更简洁,还能直接赋值。

7. 联合类型

function foo(int|string $input) {}

参数可以是多种类型。

总结

PHP 8.0 是现代 PHP 的起点,类型系统更完善,语法更现代。新项目强烈推荐用 PHP 8.0+。


emer 发布于  2026-10-4 10:34 

Git 常用命令汇总

Git 常用命令速查

Git 是开发必备工具,掌握常用命令就行,不用背太多。

1. 初始化与克隆

# 初始化仓库
git init

# 克隆远程仓库
git clone https://github.com/user/repo.git

2. 提交相关

# 查看状态
git status

# 添加到暂存区
git add .
git add file.php

# 提交
git commit -m "提交说明"

# 查看提交历史
git log --oneline

3. 分支操作

# 查看分支
git branch

# 创建分支
git branch feature

# 切换分支
git checkout feature

# 创建并切换
git checkout -b feature

# 合并分支
git merge feature

# 删除分支
git branch -d feature

4. 远程操作

# 拉取远程更新
git pull

# 推送本地提交
git push origin main

# 查看远程仓库
git remote -v

5. 撤销操作

# 撤销工作区修改
git checkout -- file.php

# 撤销暂存区
git reset HEAD file.php

# 回退到上个版本
git reset --hard HEAD~1

6. 暂存操作

# 暂存当前修改
git stash

# 恢复暂存
git stash pop

7. 标签

# 打标签
git tag v1.0.0

# 推送标签
git push origin v1.0.0

总结

日常开发就这几个命令:add、commit、push、pull、branch、merge。其他的用到再查就行,不用全背。


emer 发布于  2026-10-4 10:33 

Docker Compose 实战

Docker Compose 一键部署多容器

Docker Compose 可以用一个 YAML 文件定义和运行多个 Docker 容器,开发环境部署特别方便。

1. 基本结构

version: '3'
services:
  web:
    image: nginx
    ports:
      - "80:80"
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123456

2. 常用命令

# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 停止并删除容器
docker-compose down

# 重启某个服务
docker-compose restart web

3. PHP 开发环境示例

version: '3'
services:
  php:
    build: .
    ports:
      - "8000:80"
    volumes:
      - ./:/var/www/html
    depends_on:
      - mysql
      - redis

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:alpine

volumes:
  mysql_data:

4. 数据卷

数据卷用来持久化数据,容器删了数据还在:

volumes:
  - ./data:/var/lib/mysql

5. 网络

默认同一 Compose 里的服务在同一个网络,可以直接用服务名互相访问。比如 PHP 容器里连数据库用 mysql:3306,不用写 IP。

总结

Docker Compose 适合本地开发和测试环境。生产环境部署建议用 K8s 或者更专业的编排工具。


emer 发布于  2026-10-4 10:32 

Nginx 日志分析技巧

Nginx 日志分析常用命令

Nginx 日志是排查问题、分析流量的重要工具。掌握几个常用命令,线上排查效率翻倍。

1. 查看访问量

# 总请求数
wc -l access.log

# 今天的请求数
grep "04/Oct/2026" access.log | wc -l

2. 分析 IP 访问量

# 访问最多的前10个IP
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

3. 分析 URL 访问量

# 访问最多的前10个URL
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head -10

4. 分析状态码

# 统计各状态码数量
awk '{print $9}' access.log | sort | uniq -c | sort -nr

# 404错误数量
grep " 404 " access.log | wc -l

5. 分析流量

# 总流量
awk '{sum += $10} END {print sum/1024/1024 " MB"}' access.log

6. 实时监控

# 实时查看最新日志
tail -f access.log

# 实时查看502错误
tail -f access.log | grep " 502 "

7. 查找慢请求

# 响应时间超过1秒的请求
awk '$NF > 1' access.log | head -10

8. 排查爬虫

# 百度爬虫访问量
grep "Baiduspider" access.log | wc -l

总结

Nginx 日志分析主要靠 awk + sort + uniq 组合,掌握这几个命令,日常排查基本够用。复杂分析可以用 GoAccess 等可视化工具。


emer 发布于  2026-10-4 10:31 

Redis 持久化详解

Redis 两种持久化机制对比

Redis 是内存数据库,重启数据就没了,所以持久化很重要。Redis 有两种持久化方式:RDB 和 AOF。

1. RDB 快照

RDB 就是把整个内存数据快照存成文件。

优点:

  • 文件小,恢复快
  • 适合备份和灾难恢复

缺点:

  • 可能丢数据,两次快照之间的写入会丢

配置:

save 900 1        # 900秒内至少1个key变化就快照
save 300 10       # 300秒内至少10个key变化
save 60 10000     # 60秒内至少10000个key变化

2. AOF 日志

AOF 把每个写操作都记录到日志文件,重启时重放日志恢复数据。

优点:

  • 数据更安全,最多丢1秒
  • 日志可读,误删可以手动修复

缺点:

  • 文件比 RDB 大
  • 恢复慢

配置:

appendonly yes
appendfsync everysec   # 每秒刷盘一次

3. 混合持久化

Redis 4.0 支持混合持久化,RDB 做全量,AOF 做增量。

aof-use-rdb-preamble yes

生产环境推荐用这个,兼顾性能和数据安全。

4. 怎么选

  • 纯缓存场景:不要持久化,性能最好
  • 数据不能丢:用 AOF 或混合持久化
  • 需要快速恢复:用 RDB

总结

Redis 持久化没有完美方案,根据业务场景选。生产环境建议混合持久化,兼顾性能和数据安全。


emer 发布于  2026-10-4 10:30 

MySQL 8.0 新特性

MySQL 8.0 有哪些重要更新

MySQL 8.0 是目前最主流的大版本,相比 5.7 提升很大。

1. 性能提升

8.0 的性能比 5.7 提升约 2 倍,尤其是读取和写入并发场景下提升明显。

2. 原子 DDL

8.0 支持原子 DDL,建表、删表操作要么全成功要么全失败,不会出现一半成功一半失败的情况。

3. 窗口函数

支持窗口函数,比如 ROW_NUMBER()、RANK(),做排名统计很方便:

SELECT name, score,
  RANK() OVER (ORDER BY score DESC) as rank
FROM students;

4. CTE 公共表表达式

支持 WITH 语法,复杂 SQL 写起来更清晰:

WITH top_users AS (
  SELECT id, name FROM users WHERE vip = 1
)
SELECT * FROM top_users;

5. JSON 增强

JSON 操作函数更丰富,性能也更好,基本可以替代 MongoDB 的简单场景。

6. 隐藏索引

可以把索引设为隐藏状态,不删除但暂时不用,用来测试索引是否真的有用。

7. 字符集变化

默认字符集从 latin1 改成了 utf8mb4,支持 Emoji 表情。

总结

MySQL 8.0 是目前新项目的首选,性能好、特性全。老项目从 5.7 升级要注意兼容性,尤其是 SQL 模式和函数变化。


emer 发布于  2026-10-4 10:28 

PHP 7.4 新特性

PHP 7.4 有哪些实用新特性

PHP 7.4 是 7.x 系列的最后一个版本,带来了不少语法糖和性能优化,至今还有很多项目在用。

1. 类型属性

类的属性可以声明类型了:

class User {
    public int $id;
    public string $name;
    public ?string $email;
}

之前属性不能写类型,只能靠 PHPDoc 注释,现在直接写在代码里,IDE 提示更准确。

2. 箭头函数

支持短闭包:

$users = array_map(fn($user) => $user['name'], $users);

比传统的 function ($user) use (...) {} 简洁多了,自动捕获外层变量。

3. 空合并赋值

$data['user'] ??= [];

相当于:

if (!isset($data['user'])) {
    $data['user'] = [];
}

4. 数组展开

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = [...$arr1, ...$arr2];

5. 数字字面量分隔

$amount = 1_000_000;
$price = 9_999.99;

大数字用下划线分隔,可读性提升。

6. 性能提升

PHP 7.4 比 7.3 性能提升约 10%,内存占用也更少。

总结

PHP 7.4 虽然不是大版本,但实用特性很多,尤其是类型属性和箭头函数,写起来舒服不少。新项目建议直接上 PHP 8+,老项目升级到 7.4 也很稳妥。


emer 发布于  2026-10-4 10:27 

PHP Session 与 Cookie:会话管理实战指南

前言

HTTP 是无状态的,你每次请求服务器都不认识你。Session 和 Cookie 就是用来解决这个问题的。本文讲清楚 PHP 中 Session 和 Cookie 的用法。

一、Cookie 是什么

Cookie 是存在浏览器里的小数据,每次请求自动带给服务器。

设置 Cookie

setcookie("username", "张三", time() + 3600, "/");

参数说明:

  • 第一个参数:名称
  • 第二个参数:值
  • 第三个参数:过期时间(时间戳)
  • 第四个参数:路径

读取 Cookie

echo $_COOKIE['username'];

删除 Cookie

setcookie("username", "", time() - 3600, "/");

把过期时间设成过去就行。

二、Session 是什么

Session 是存在服务器上的数据,通过 Session ID 识别用户。

启动 Session

session_start();

注意:必须在输出之前调用,不然会报错。

存数据

$_SESSION['user_id'] = 1;
$_SESSION['username'] = '张三';

读数据

echo $_SESSION['username'];

删除单个数据

unset($_SESSION['user_id']);

销毁 Session

session_destroy();

三、Session 和 Cookie 的区别

对比 Cookie Session
存储位置 浏览器 服务器
大小限制 4KB 无限制
安全性 低(用户能改) 高
生命周期 可设置 默认浏览器关闭就没

四、登录功能示例

登录页

<?php
session_start();

if ($_POST) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // 验证用户名密码
    if ($username == 'admin' && $password == '123456') {
        $_SESSION['user_id'] = 1;
        $_SESSION['username'] = $username;
        header('Location: dashboard.php');
        exit;
    } else {
        echo "用户名或密码错误";
    }
}
?>

判断是否登录

<?php
session_start();

if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}
?>

退出登录

<?php
session_start();
session_destroy();
header('Location: login.php');
exit;
?>

五、Session 配置

修改 Session 有效期

ini_set('session.gc_maxlifetime', 3600); // 1小时
session_start();

修改 Session 存储路径

session_save_path('/tmp/sessions');
session_start();

用 Redis 存储 Session

生产环境推荐用 Redis 存 Session,默认文件存储性能差。

php.ini 配置:

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

六、安全问题

1. Session 劫持

别人拿到你的 Session ID,就能冒充你。

防护:

  • 用 HTTPS
  • Session ID 定期更换
  • 绑定 IP(不太推荐,IP 会变)

2. Cookie 劫持

别人拿到你的 Cookie,就能冒充你。

防护:

  • 设置 HttpOnly,JS 读不到
  • 设置 Secure,只在 HTTPS 下传
  • 设置 SameSite,防止 CSRF
setcookie("token", $token, [
    'expires' => time() + 3600,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

3. CSRF 攻击

别人伪造你的请求。

防护:

  • 表单加 CSRF Token
  • 验证 Referer

七、常见坑

  1. session_start() 在输出之后:报错 headers already sent
  2. Session 没销毁:退出登录后还能访问
  3. Cookie 大小限制:别存太多东西,超过 4KB 就丢
  4. Session 文件太多:默认文件存储,大了要清理

八、最佳实践

  1. 敏感数据用 Session,别存 Cookie
  2. Cookie 加 HttpOnly 和 Secure
  3. 生产环境用 Redis 存 Session
  4. 登录成功后重新生成 Session ID,防止固定攻击
// 登录成功后
session_regenerate_id(true);

总结

Session 和 Cookie 的核心要点:

  1. Cookie 存在浏览器,Session 存在服务器
  2. session_start() 必须在输出之前调用
  3. Session 更安全,Cookie 更轻量
  4. 生产环境用 Redis 存 Session
  5. Cookie 加 HttpOnly 和 Secure,防劫持

登录、权限、购物车,都离不开 Session 和 Cookie。搞懂这俩,PHP 后端才算入门。


emer 发布于  2026-10-4 10:21 

PHP Composer 入门:依赖管理完全指南

前言

Composer 是 PHP 的依赖管理工具,就像 Node 的 npm、Python 的 pip。现在写 PHP 项目,不会 Composer 根本没法干活。本文讲清楚 Composer 的核心用法。

一、安装 Composer

Linux / Mac

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Windows

去官网下载安装包,一路下一步就行。

验证安装

composer -V

二、初始化项目

# 在项目目录下
composer init

会问你几个问题,一路回车就行,然后会生成 composer.json 文件。

composer.json 长什么样

{
    "name": "yourname/project",
    "description": "项目描述",
    "require": {
        "monolog/monolog": "^2.0"
    }
}

三、安装依赖

1. 安装所有依赖

composer install

会根据 composer.lock 文件安装指定版本的依赖。

2. 添加新依赖

composer require monolog/monolog

会自动加到 composer.json 里,然后安装。

3. 安装指定版本

composer require monolog/monolog:^2.0

版本号说明

  • ^2.0:2.0 到 3.0 之前(不包括 3.0)
  • ~2.0:2.0 到 2.1 之前(不包括 2.1)
  • *:任意版本
  • 2.0.*:2.0 开头的版本

四、自动加载

Composer 最爽的就是自动加载,不用自己写 require。

引入自动加载

<?php
require 'vendor/autoload.php';

// 直接用类,不用 require
$log = new Monolog\Logger('name');

PSR-4 自动加载

在 composer.json 里配置:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

然后执行:

composer dump-autoload

这样 App\User 类就会从 src/User.php 加载。

五、常用命令

命令 作用
composer install 安装所有依赖
composer update 更新所有依赖
composer require 包名 添加依赖
composer remove 包名 删除依赖
composer dump-autoload 重新生成自动加载
composer show 查看已安装的包
composer self-update 更新 Composer 本身

六、开发环境依赖

有些包只在开发时用,比如测试工具:

composer require --dev phpunit/phpunit

线上部署的时候,不安装开发依赖:

composer install --no-dev

七、中国镜像

国外源太慢,换中国镜像:

# 阿里云镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

# 腾讯云镜像
composer config -g repo.packagist composer https://mirrors.tencent.com/composer/

换完之后速度飞起来。

八、composer.lock 的作用

  • 记录当前安装的依赖版本
  • 团队成员 install 的时候,装的版本一模一样
  • 一定要提交到 Git
git add composer.json composer.lock
git commit -m "update composer"

九、常见坑

  1. 没装 composer.lock:团队成员装的版本不一样,出 bug
  2. 自动加载不生效:改了 autoload 配置,忘了 dump-autoload
  3. 版本冲突:两个包依赖同一个库的不同版本
  4. 国内太慢:不换镜像,下载半天

十、最佳实践

  1. composer.json 和 composer.lock 都提交 Git
  2. 线上用 install --no-dev,不要用 update
  3. 用中文镜像,加速下载
  4. 改了自动加载配置,记得 dump-autoload

总结

Composer 的核心要点:

  1. require 添加依赖,install 安装依赖
  2. vendor/autoload.php 是自动加载入口
  3. composer.lock 要提交 Git,保证版本一致
  4. 换国内镜像,速度快很多
  5. 开发依赖用 --dev,线上不装

学会 Composer,PHP 开发效率提升一倍。


emer 发布于  2026-10-4 10:20 

MySQL 备份与恢复:mysqldump 实战指南

前言

数据库备份是生产环境的生命线。很多人没出事的时候不备份,出事了才后悔。本文讲清楚 MySQL 最常用的备份工具 mysqldump。

一、为什么要备份

  • 误操作:手滑删了表、删了数据
  • 服务器挂了:硬盘坏了、机器报废
  • 被攻击: ransomware 加密了数据库
  • 升级失败:新版本不兼容,数据回退

记住:没有备份的数据库,就是在裸奔。

二、mysqldump 是什么

mysqldump 是 MySQL 自带的逻辑备份工具,把数据导出成 SQL 文件。

优点:简单、通用、跨版本
缺点:大数据量慢

适合:中小数据库(< 50G)

三、备份数据库

1. 备份整个数据库

mysqldump -u root -p 数据库名 > backup.sql

输入密码后,就会生成 backup.sql 文件。

2. 备份所有数据库

mysqldump -u root -p --all-databases > all_backup.sql

3. 备份单个表

mysqldump -u root -p 数据库名 表名 > table_backup.sql

4. 备份多个表

mysqldump -u root -p 数据库名 表1 表2 > multi_backup.sql

四、恢复数据库

1. 恢复整个数据库

mysql -u root -p 数据库名 < backup.sql

注意:数据库要先存在。

CREATE DATABASE 数据库名;

2. 恢复所有数据库

mysql -u root -p < all_backup.sql

五、常用参数

--single-transaction

InnoDB 引擎下,保证备份一致性,不锁表:

mysqldump -u root -p --single-transaction 数据库名 > backup.sql

生产环境一定要加这个!

--routines

备份存储过程和函数:

mysqldump -u root -p --routines 数据库名 > backup.sql

--triggers

备份触发器:

mysqldump -u root -p --triggers 数据库名 > backup.sql

--events

备份事件调度器:

mysqldump -u root -p --events 数据库名 > backup.sql

--no-data

只备份表结构,不备份数据:

mysqldump -u root -p --no-data 数据库名 > schema.sql

--where

按条件备份:

mysqldump -u root -p 数据库名 表名 --where="id > 100" > partial.sql

六、完整备份命令

生产环境推荐用这个:

mysqldump -u root -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --default-character-set=utf8mb4 \
  数据库名 > backup.sql

七、压缩备份

备份文件太大?压缩一下:

# 备份并压缩
mysqldump -u root -p 数据库名 | gzip > backup.sql.gz

# 解压并恢复
gunzip < backup.sql.gz | mysql -u root -p 数据库名

八、定时备份

写个脚本每天自动备份:

#!/bin/bash

# 备份目录
BACKUP_DIR="/data/backup/mysql"
DATE=$(date +%Y%m%d)

# 备份
mysqldump -u root -p密码 --single-transaction 数据库名 | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# 删除 7 天前的备份
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete

加到 crontab:

# 每天凌晨 2 点备份
0 2 * * * /bin/bash /path/to/backup.sh

九、常见坑

  1. 备份不锁表:大表备份会锁表,一定要加 --single-transaction
  2. 字符集不对:备份文件乱码,加 --default-character-set=utf8mb4
  3. 没备份存储过程:导出后丢了,加 --routines
  4. 备份没验证:备份完一定要试恢复,不然真出事的时候哭都来不及

十、备份策略

  • 每天全量备份:小数据库
  • 每周全量 + 每天增量:大数据库
  • 异地备份:备份文件要存到别的服务器
  • 定期演练恢复:每个月测一次能不能恢复

总结

MySQL 备份的核心要点:

  1. mysqldump 是最常用的备份工具
  2. 生产环境加 --single-transaction,不锁表
  3. 备份要压缩,节省空间
  4. 定时备份,自动删除旧备份
  5. 备份一定要验证,能恢复才算备份成功

数据是公司最值钱的资产,备份这事儿千万别偷懒。


emer 发布于  2026-10-4 10:18 

Linux 常用命令:从文件操作到进程管理的完整指南

前言

Linux 是后端开发的必修课。很多新手面对黑窗口就发怵,其实只要掌握常用命令,日常开发就够用了。本文整理最常用的 Linux 命令。

一、文件操作

1. 查看目录

# 列出当前目录文件
ls

# 详细信息
ls -l

# 包括隐藏文件
ls -la

# 按时间排序
ls -lt

2. 切换目录

# 进入目录
cd /home/user

# 回到上一级
cd ..

# 回到用户主目录
cd ~

# 回到上次目录
cd -

3. 创建目录

# 创建目录
mkdir test

# 递归创建多级目录
mkdir -p a/b/c

4. 创建文件

# 创建空文件
touch test.txt

# 写入内容
echo "hello" > test.txt

# 追加内容
echo "world" >> test.txt

5. 复制文件

# 复制文件
cp test.txt test2.txt

# 复制目录
cp -r dir1 dir2

6. 移动/重命名

# 移动文件
mv test.txt /tmp/

# 重命名
mv old.txt new.txt

7. 删除文件

# 删除文件
rm test.txt

# 删除目录
rm -rf dir1

警告:rm -rf 很危险,一定要确认路径!

二、查看文件内容

1. cat

# 查看整个文件
cat test.txt

2. less

# 分页查看
less test.log

# 快捷键:
# 空格:下一页
# b:上一页
# /关键字:搜索
# q:退出

3. head / tail

# 看前 10 行
head -10 test.txt

# 看后 10 行
tail -10 test.txt

# 实时看日志(最常用)
tail -f /var/log/nginx/access.log

三、查找文件

1. find

# 按文件名查找
find / -name "nginx.conf"

# 按大小查找(大于 100M)
find / -size +100M

# 按修改时间查找(7 天内修改的)
find / -mtime -7

2. grep

# 在文件里搜索
grep "error" test.log

# 不区分大小写
grep -i "error" test.log

# 显示行号
grep -n "error" test.log

# 递归搜索目录
grep -r "function" /var/www/

# 配合管道使用
ps aux | grep nginx

四、系统状态

1. 查看进程

# 所有进程
ps aux

# 查找进程
ps aux | grep nginx

2. 杀死进程

# 按 PID 杀
kill 1234

# 强制杀
kill -9 1234

# 按名字杀
pkill nginx

3. 查看端口

# 查看所有监听端口
netstat -tlnp

# 查看某个端口
netstat -tlnp | grep 80

4. 查看磁盘

# 磁盘使用情况
df -h

# 当前目录大小
du -sh .

# 每个子目录大小
du -sh *

5. 查看内存

free -h

五、权限管理

1. chmod

# 给文件加执行权限
chmod +x test.sh

# 755:所有者可读写执行,其他人可读执行
chmod 755 test.sh

# 644:所有者可读写,其他人只读
chmod 644 test.txt

2. chown

# 修改文件所有者
chown www:www test.txt

六、压缩解压

1. tar

# 压缩
tar -zcvf website.tar.gz /var/www/html

# 解压
tar -zxvf website.tar.gz

2. zip

# 压缩
zip -r website.zip /var/www/html

# 解压
unzip website.zip

七、网络相关

1. curl

# 访问网页
curl https://www.baidu.com

# 查看响应头
curl -I https://www.baidu.com

# 发 POST 请求
curl -X POST -d "name=张三" https://api.example.com

2. wget

# 下载文件
wget https://example.com/file.zip

八、常用快捷键

快捷键 作用
Ctrl + C 终止当前命令
Ctrl + Z 暂停当前命令
Ctrl + D 退出终端
Tab 自动补全
Ctrl + R 搜索历史命令
!命令 执行最近一次的某命令

九、常用操作速查

操作 命令
看文件 cat / less / tail -f
找文件 find / grep
看进程 ps aux / top
看端口 netstat -tlnp
看磁盘 df -h / du -sh
改权限 chmod / chown

总结

Linux 常用命令的核心要点:

  1. 文件操作:ls / cd / mkdir / cp / mv / rm
  2. 查看内容:cat / less / tail -f
  3. 查找搜索:find / grep
  4. 进程管理:ps / kill / netstat
  5. 系统状态:df / du / free

不用背,用多了自然就记住了。先把这几个常用的练熟,日常开发基本够用。


emer 发布于  2026-10-4 10:17 

PHP 数组常用操作:从排序到过滤的完整指南

前言

数组是 PHP 里最常用的数据结构,没有之一。PHP 提供了 100 多个数组函数,很多人只知道其中几个。本文整理最常用的数组操作。

一、创建数组

<?php
// 索引数组
$arr1 = [1, 2, 3, 4, 5];

// 关联数组
$arr2 = ['name' => '张三', 'age' => 18];

// 空数组
$arr3 = [];

二、添加元素

<?php
$arr = [1, 2, 3];

// 末尾添加
$arr[] = 4; // [1, 2, 3, 4]
array_push($arr, 5); // [1, 2, 3, 4, 5]

// 开头添加
array_unshift($arr, 0); // [0, 1, 2, 3, 4, 5]

// 关联数组添加
$user = ['name' => '张三'];
$user['age'] = 18; // ['name' => '张三', 'age' => 18]

三、删除元素

<?php
$arr = [1, 2, 3, 4, 5];

// 删除末尾元素
array_pop($arr); // [1, 2, 3, 4]

// 删除开头元素
array_shift($arr); // [2, 3, 4]

// 删除指定元素
unset($arr[1]); // [0 => 2, 2 => 4],注意索引不连续

四、查找元素

<?php
$arr = ['a', 'b', 'c'];

// 值是否存在
in_array('b', $arr); // true

// 键是否存在
$user = ['name' => '张三', 'age' => 18];
array_key_exists('name', $user); // true

// 查找值的键
array_search('b', $arr); // 1

五、数组长度

<?php
$arr = [1, 2, 3];
count($arr); // 3
sizeof($arr); // 3(count 的别名)

六、排序

索引数组排序

<?php
$arr = [3, 1, 2, 5, 4];

sort($arr); // [1, 2, 3, 4, 5] 升序
rsort($arr); // [5, 4, 3, 2, 1] 降序

关联数组排序

<?php
$age = ['张三' => 20, '李四' => 18, '王五' => 25];

asort($age); // 按值升序,保持键名
ksort($age); // 按键升序
arsort($age); // 按值降序
krsort($age); // 按键降序

自定义排序

<?php
$users = [
    ['name' => '张三', 'age' => 20],
    ['name' => '李四', 'age' => 18],
    ['name' => '王五', 'age' => 25],
];

// 按 age 升序
usort($users, function ($a, $b) {
    return $a['age'] <=> $b['age'];
});

七、数组过滤

array_filter()

<?php
$arr = [1, 2, 3, 4, 5, 6];

// 过滤出偶数
$even = array_filter($arr, function ($n) {
    return $n % 2 == 0;
});
// [2, 4, 6]

array_map()

<?php
$arr = [1, 2, 3, 4, 5];

// 每个元素乘以 2
$doubled = array_map(function ($n) {
    return $n * 2;
}, $arr);
// [2, 4, 6, 8, 10]

array_walk()

<?php
$arr = ['a' => 1, 'b' => 2];

array_walk($arr, function (&$value, $key) {
    $value = $value * 10;
});
// ['a' => 10, 'b' => 20]

八、数组合并

<?php
$arr1 = [1, 2];
$arr2 = [3, 4];

// 数组合并
$merged = array_merge($arr1, $arr2); // [1, 2, 3, 4]

// + 运算符(保留第一个数组的键)
$result = $arr1 + $arr2;

九、数组切片

<?php
$arr = [1, 2, 3, 4, 5];

// 从第 2 个开始取 3 个
$slice = array_slice($arr, 1, 3); // [2, 3, 4]

// 从末尾取
$last = array_slice($arr, -2); // [4, 5]

十、键值操作

<?php
$user = ['name' => '张三', 'age' => 18];

// 所有键
array_keys($user); // ['name', 'age']

// 所有值
array_values($user); // ['张三', 18]

// 翻转键值
array_flip($user); // ['张三' => 'name', 18 => 'age']

十一、常用操作速查表

操作 函数
数组长度 count()
查找值 in_array()
查找键 array_key_exists()
排序 sort() / asort() / ksort()
过滤 array_filter()
映射 array_map()
合并 array_merge()
切片 array_slice()

十二、常见坑

  1. unset 后索引不连续:用 array_values() 重新索引
  2. array_merge 和 + 的区别:数字键 array_merge 会重新索引,+ 不会
  3. in_array 严格模式:加第三个参数 true 防止类型转换
  4. sort 会改变原数组:不是返回新数组

总结

PHP 数组操作的核心要点:

  1. 增删改查:array_push/pop/unshift/shift/unset
  2. 查找判断:in_array/array_key_exists/array_search
  3. 排序:sort/asort/ksort/usort
  4. 处理:array_filter/array_map/array_walk
  5. 合并切片:array_merge/array_slice

数组用好了,PHP 开发效率能提升一倍。


emer 发布于  2026-10-4 10:15 

Redis 数据结构:五种常用类型和应用场景实战

前言

Redis 不只是简单的缓存,它有 5 种常用数据结构,每种都有特定的应用场景。用对了能解决很多问题,用错了就是浪费内存。本文讲清楚这 5 种数据结构。

一、String(字符串)

是什么

最简单的 key-value 结构,value 可以是字符串、数字、二进制。

常用命令

# 设置值
SET name "张三"

# 获取值
GET name

# 数字自增
INCR count
INCRBY count 10

# 设置过期时间
SETEX session:token 3600 "abc123"

# 批量操作
MSET name "张三" age 18 city "北京"
MGET name age city

应用场景

  1. 缓存:缓存用户信息、配置
  2. 计数器:文章阅读数、点赞数
  3. 分布式锁:SETNX 命令
  4. Session 存储:用户登录状态

二、Hash(哈希)

是什么

一个 key 对应一个 map,适合存储对象。

常用命令

# 设置单个字段
HSET user:1 name "张三"
HSET user:1 age 18

# 获取单个字段
HGET user:1 name

# 获取所有字段
HGETALL user:1

# 批量设置
HMSET user:1 name "张三" age 18 city "北京"

# 字段自增
HINCRBY user:1 age 1

应用场景

  1. 存储对象:用户信息、商品信息
  2. 购物车:key 是用户 ID,field 是商品 ID,value 是数量
# 购物车
HSET cart:1001 商品A 2
HSET cart:1001 商品B 1

三、List(列表)

是什么

有序列表,底层是双向链表,可以从左右两边 push/pop。

常用命令

# 左边插入
LPUSH messages "hello"
LPUSH messages "world"

# 右边插入
RPUSH messages "end"

# 左边弹出
LPOP messages

# 右边弹出
RPOP messages

# 查看列表范围
LRANGE messages 0 -1

# 列表长度
LLEN messages

应用场景

  1. 消息队列:LPUSH + RPOP
  2. 最新消息:比如最新评论、最新文章
  3. 朋友圈时间线:LPUSH 新内容,LRANGE 分页查看

四、Set(集合)

是什么

无序且不重复的集合,自动去重。

常用命令

# 添加元素
SADD tags "PHP" "MySQL" "Redis"

# 查看所有元素
SMEMBERS tags

# 判断元素是否存在
SISMEMBER tags "PHP"

# 集合运算
SINTER set1 set2  # 交集
SUNION set1 set2  # 并集
SDIFF set1 set2   # 差集

# 集合大小
SCARD tags

应用场景

  1. 标签系统:一篇文章的标签
  2. 共同好友:SINTER 算交集
  3. 去重:UV 统计、防止重复提交
  4. 抽奖:SRANDMEMBER 随机抽取

五、ZSet(有序集合)

是什么

每个元素都有一个 score,按 score 排序,不重复。

常用命令

# 添加元素
ZADD rank 100 "张三"
ZADD rank 90 "李四"
ZADD rank 95 "王五"

# 按分数从低到高排序
ZRANGE rank 0 -1 WITHSCORES

# 按分数从高到低排序
ZREVRANGE rank 0 -1 WITHSCORES

# 查看元素排名
ZREVRANK rank "张三"

# 查看元素分数
ZSCORE rank "张三"

# 分数范围查询
ZRANGEBYSCORE rank 90 100

应用场景

  1. 排行榜:直播间送礼排行、游戏排行
  2. 延迟队列:score 存时间戳,到点的任务处理
  3. 加权排序:搜索结果排序

六、怎么选数据结构

场景 用什么
简单 key-value String
存对象 Hash
有序列表/队列 List
去重/标签 Set
排序/排行 ZSet

七、常见坑

  1. List 太多元素:链表太长,范围查询慢
  2. Hash 字段太多:小对象还好,大对象不适合
  3. Set 当 List 用:Set 无序,要顺序用 List 或 ZSet
  4. 大 key:一个 key 存几百万数据,会阻塞

总结

Redis 5 种数据结构的核心要点:

  1. String:最简单,缓存、计数器
  2. Hash:存对象,用户信息、购物车
  3. List:有序队列,消息、时间线
  4. Set:去重集合,标签、共同好友
  5. ZSet:排序集合,排行榜、延迟队列

选对数据结构,Redis 才能发挥最大威力。


emer 发布于  2026-10-4 10:14 

PHP 字符串处理:常用函数和最佳实践指南

前言

字符串处理是 PHP 开发中最常用的操作之一。很多人写了很多年代码,却还是用错字符串函数。本文整理最常用的字符串处理函数和最佳实践。

一、字符串长度

strlen()

<?php
$str = "hello";
echo strlen($str); // 5

注意:strlen 按字节算,中文会出问题。

mb_strlen()

<?php
$str = "你好";
echo mb_strlen($str, 'UTF-8'); // 2
echo strlen($str); // 6(3个字节一个汉字)

记住:处理中文一定要用 mb_ 系列函数。

二、字符串查找

strpos()

查找字符串第一次出现的位置:

<?php
$str = "hello world";
$pos = strpos($str, "world");
echo $pos; // 6

坑: 如果没找到返回 false,如果找到的位置是 0,也返回 0。

<?php
// 错误写法
if (strpos($str, "hello")) {
    // 如果 hello 在第 0 位,这里不会执行
}

// 正确写法
if (strpos($str, "hello") !== false) {
    // 这样才对
}

strrpos()

查找字符串最后一次出现的位置。

stripos() / strripos()

不区分大小写的查找。

三、字符串替换

str_replace()

<?php
$str = "hello world";
echo str_replace("world", "PHP", $str); // hello PHP

数组替换:

<?php
echo str_replace(
    ["hello", "world"],
    ["hi", "PHP"],
    "hello world"
); // hi PHP

substr_replace()

替换字符串的一部分:

<?php
echo substr_replace("hello world", "PHP", 6); // hello PHP

preg_replace()

正则替换:

<?php
// 把多个空格变成一个
echo preg_replace('/\s+/', ' ', "hello   world"); // hello world

四、字符串截取

substr()

<?php
$str = "hello world";
echo substr($str, 0, 5); // hello
echo substr($str, 6); // world

中文截取要用 mb_substr():

<?php
$str = "你好世界";
echo mb_substr($str, 0, 2, 'UTF-8'); // 你好

五、字符串分割与连接

explode()

<?php
$str = "a,b,c,d";
$arr = explode(",", $str);
print_r($arr); // ['a', 'b', 'c', 'd']

implode() / join()

<?php
$arr = ['a', 'b', 'c'];
echo implode(",", $arr); // a,b,c

六、字符串去空格

trim()

<?php
$str = "  hello  ";
echo trim($str); // "hello",去掉两边空格
echo ltrim($str); // "hello  ",去掉左边空格
echo rtrim($str); // "  hello",去掉右边空格

七、大小写转换

<?php
$str = "Hello World";
echo strtolower($str); // hello world
echo strtoupper($str); // HELLO WORLD
echo ucfirst($str); // Hello world
echo ucwords($str); // Hello World

八、HTML 转义

htmlspecialchars()

输出到 HTML 时一定要转义,防止 XSS:

<?php
$str = "<script>alert('xss')</script>";
echo htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
// 输出 &lt;script&gt;alert(&#039;xss&#039;)&lt;/script&gt;

htmlentities()

更彻底的转义,把所有 HTML 都转义。

九、JSON 处理

json_encode()

<?php
$arr = ['name' => '张三', 'age' => 18];
echo json_encode($arr, JSON_UNESCAPED_UNICODE);
// {"name":"张三","age":18}

记住:加 JSON_UNESCAPED_UNICODE,不然中文会变成 \uXXXX。

json_decode()

<?php
$json = '{"name":"张三","age":18}';
$obj = json_decode($json); // 对象
$arr = json_decode($json, true); // 数组

十、常见坑

  1. strpos 用 == 判断:位置 0 和 false 会混淆
  2. 中文用 strlen/substr:按字节算,中文会乱码
  3. 输出 HTML 不转义:XSS 漏洞
  4. json_encode 不加 JSON_UNESCAPED_UNICODE:中文变 \uXXXX
  5. 字符串拼接用 . 不用 +:PHP 是 . 号

总结

PHP 字符串处理的核心要点:

  1. 中文用 mb_ 系列函数,不要用 strlen/substr
  2. strpos 用 !== false 判断,不要用 ==
  3. 输出 HTML 一定要 htmlspecialchars 转义
  4. json_encode 加 JSON_UNESCAPED_UNICODE
  5. 字符串拼接用 . 号,不要用 + 号

掌握这些,字符串处理就不会出大问题了。


emer 发布于  2026-10-4 10:12