MySQL报错"Table 'xxx' doesn't exist"解决
前言
查询数据库时报错:Table 'xxx' doesn't exist,明明表就在那,为什么说不存在?本文排查常见原因。
报错长什么样
SELECT * FROM users;
报错:
ERROR 1146 (42S02): Table 'mydb.users' doesn't exist
常见原因
原因1:数据库选错了
当前在别的库里,所以找不到表。
排查: 先看当前在哪个库:
SELECT DATABASE();
如果显示的不是你要的库,就切换:
USE mydb;
再查一次。
原因2:表名写错了
拼错了,或者大小写不对。
排查: 看看库里到底有哪些表:
SHOW TABLES;
确认表名是不是和你写的一模一样。
注意: Linux下MySQL表名区分大小写,Users 和 users 是两个表。
原因3:表真的被删了
表确实不存在了,可能被误删了。
排查: 用SHOW TABLES确认。如果真没有,从备份恢复。
原因4:字符集导致的问题
表名里有特殊字符,编码不对导致识别不出来。
排查: 用 SHOW TABLES LIKE 'xxx%'; 模糊匹配一下。
原因5:MySQL升级后表损坏
升级MySQL后,某些表报错不存在,但文件还在。
原因: 表引擎损坏,或者frm文件丢了。
排查: 看数据目录下有没有对应文件:
ls /var/lib/mysql/mydb/
原因6:用户没有权限
虽然报错是"不存在",但有时候权限不够也会这么报。
排查: 用root用户登录试试,如果root能看到,就是权限问题。
排查步骤
第一步:确认当前数据库
SELECT DATABASE();
第二步:查看所有表
SHOW TABLES;
第三步:模糊搜索表名
SHOW TABLES LIKE '%user%';
第四步:确认表文件是否存在
ls /var/lib/mysql/你的库名/ | grep 表名
常见坑
坑1:Linux下表名区分大小写
Windows开发没问题,上传到Linux服务器就报错。
解决: 表名统一用小写,或者在my.cnf加:
lower_case_table_names = 1
注意: 这个参数只能在初始化MySQL前设置,已经用了再改会出问题。
坑2:分表了忘了加表名
用了分表,代码里查的是 users,实际表名是 users_0、users_1。
解决: 确认分表规则,代码里拼对表名。
坑3:视图报错
查视图时报"表不存在",可能是视图依赖的表被删了。
排查: 看视图定义:
SHOW CREATE VIEW 视图名;
坑4:临时表
会话结束临时表就没了,新开一个连接查就报错。
解决: 临时表只在当前会话有效,别跨连接用。
坑5:误删了库
整个库都没了,当然找不到表。
排查:
SHOW DATABASES;
看你的库还在不在。
总结
排查顺序:
- 先看当前在哪个库
- 再SHOW TABLES看表在不在
- 确认表名大小写对不对
- 最后看数据目录下文件在不在
记住: 90%的情况都是库选错了或者表名写错了。
遇到问题加QQ23979811 协助处理
MySQL查看表结构,desc和show create table
前言
接手别人的项目,不知道表有哪些字段、什么类型、有没有索引,全靠DESC和SHOW CREATE TABLE。
一、查看表有哪些字段
方法1:DESC(最常用)
DESC users;
或者:
DESCRIBE users;
输出:
| Field | Type | Null | Key | Default | Extra |
|---|---|---|---|---|---|
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | NULL | ||
| age | int(11) | YES | NULL |
每列含义:
- Field:字段名
- Type:字段类型
- Null:能不能为NULL
- Key:有没有索引
- Default:默认值
- Extra:额外属性(自增等)
方法2:SHOW COLUMNS
SHOW COLUMNS FROM users;
和DESC效果一样,写法不同而已。
二、查看建表语句
SHOW CREATE TABLE
SHOW CREATE TABLE users;
输出:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
这个命令能看到:
- 完整的建表SQL
- 所有字段和类型
- 主键、索引
- 表引擎、字符集
- 默认值、自增等
三、查看表状态
SHOW TABLE STATUS LIKE 'users'\G
能看到:
- 表行数
- 数据大小
- 索引大小
- 更新时间
- 引擎类型
- 字符集
四、查看表的所有索引
SHOW INDEX FROM users;
或者:
SHOW KEYS FROM users;
五、查看数据库里所有表
SHOW TABLES;
六、实用组合
查看所有表的表名
SHOW TABLES;
查看某库的表
USE 数据库名;
SHOW TABLES;
或者:
SHOW TABLES FROM 数据库名;
七、从information_schema查
更灵活的方式,从系统表查:
查表的字段信息
SELECT * FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb'
AND TABLE_NAME = 'users';
查表的索引信息
SELECT * FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'mydb'
AND TABLE_NAME = 'users';
常见坑
坑1:DESC看不到索引详细信息
DESC只告诉你Key列是啥,但不知道索引名。
解决: 用 SHOW INDEX FROM 表名;
坑2:SHOW CREATE TABLE输出太长
直接看会换行很乱。
解决: 加 \G 按行显示:
SHOW CREATE TABLE users\G
坑3:不知道当前在哪个库
查的时候报错说表不存在。
解决: 先 SELECT DATABASE(); 看当前库。
坑4:表名大小写问题
Linux下MySQL表名区分大小写,Windows不区分。
解决: 表名小写,开发时注意。
总结
常用命令总结:
| 命令 | 作用 |
|---|---|
DESC 表名 |
看字段列表 |
SHOW CREATE TABLE 表名 |
看完整建表语句 |
SHOW INDEX FROM 表名 |
看索引 |
SHOW TABLES |
看所有表 |
SHOW TABLE STATUS |
看表状态 |
记住: 看表结构首选DESC,要看完整建表语句用SHOW CREATE TABLE。
遇到问题加QQ23979811 协助处理
MySQL备份数据库,mysqldump定时备份
前言
数据库不备份,出事就完蛋。本文讲用mysqldump备份MySQL,再配crontab定时自动备份。
一、mysqldump基本用法
备份单个数据库
mysqldump -u root -p mydb > /backup/mydb.sql
输入密码后,就把mydb库备份到mydb.sql了。
备份多个数据库
mysqldump -u root -p --databases db1 db2 > /backup/mydbs.sql
备份所有数据库
mysqldump -u root -p --all-databases > /backup/all.sql
备份单个表
mysqldump -u root -p mydb users > /backup/users.sql
二、常用参数
| 参数 | 说明 |
|---|---|
--single-transaction |
InnoDB一致性备份,不锁表 |
--routines |
备份存储过程和函数 |
--triggers |
备份触发器 |
--events |
备份事件调度器 |
--master-data=2 |
记录binlog位置,用于主从 |
--default-character-set=utf8mb4 |
指定字符集 |
推荐完整命令
mysqldump -u root -p \
--single-transaction \
--routines \
--triggers \
--events \
--default-character-set=utf8mb4 \
mydb > /backup/mydb_$(date +%Y%m%d).sql
三、压缩备份
备份完太大,直接压缩:
mysqldump -u root -p mydb | gzip > /backup/mydb.sql.gz
恢复的时候:
gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb
四、定时备份脚本
创建备份脚本:
vi /usr/local/bin/mysql_backup.sh
内容:
#!/bin/bash
# 备份目录
BACKUP_DIR=/backup/mysql
# 数据库配置
DB_USER=root
DB_PASS=你的密码
DB_NAME=mydb
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份文件名(带日期)
DATE=$(date +%Y%m%d_%H%M%S)
FILE=$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz
# 执行备份
mysqldump -u$DB_USER -p$DB_PASS \
--single-transaction \
--routines \
--triggers \
--default-character-set=utf8mb4 \
$DB_NAME | gzip > $FILE
# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
echo "备份完成:$FILE"
加执行权限:
chmod +x /usr/local/bin/mysql_backup.sh
五、配置crontab定时任务
编辑crontab:
crontab -e
加上:
# 每天凌晨2点备份
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
六、恢复备份
恢复普通备份
mysql -u root -p mydb < /backup/mydb.sql
恢复压缩备份
gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb
常见坑
坑1:密码写在命令行里不安全
mysqldump -u root -p123456 mydb > xxx.sql
这样密码会出现在进程列表里。
安全做法: 用配置文件存密码。
# /root/.my.cnf
[mysqldump]
user=root
password=你的密码
权限设600:
chmod 600 /root/.my.cnf
以后备份就不用输密码了:
mysqldump mydb > xxx.sql
坑2:备份时锁表
大库备份的时候,业务卡住了。
原因: 没加 --single-transaction。
解决: InnoDB库一定要加这个参数。
坑3:备份文件是空的
备份完一看,文件0字节。
原因: 密码错了,或者数据库名错了。
解决: 先手动执行一次,看报错。
坑4:备份没包含存储过程
备份后恢复,发现存储过程没了。
原因: mysqldump默认不备份存储过程。
解决: 加 --routines 参数。
总结
三步搞定自动备份:
- 写备份脚本
- 配crontab定时执行
- 定期清理旧备份
记住: 备份了不算数,能恢复才算数。
遇到问题加QQ23979811 协助处理
MySQL创建数据库、创建用户、授权完整命令
前言
新装MySQL,要创建数据库、创建用户、授权,一套操作下来经常懵。本文整理完整命令,照着抄就行。
第一步:登录MySQL
mysql -u root -p
输入root密码登录。
第二步:创建数据库
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
说明:
mydb是数据库名,自己改utf8mb4支持emoji,推荐用utf8mb4_general_ci是排序规则
第三步:创建用户
MySQL 5.7及以前
CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';
MySQL 8.0
CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';
允许远程登录
CREATE USER 'myuser'@'%' IDENTIFIED BY '你的密码';
% 表示所有IP都能连,生产环境建议指定具体IP。
第四步:授权
授权所有权限(常用)
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
说明:
mydb.*表示mydb库下所有表- 要授权所有库就写
*.*
只授权查询权限
GRANT SELECT ON mydb.* TO 'myuser'@'localhost';
授权指定权限
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'myuser'@'localhost';
授权远程用户
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%';
第五步:刷新权限
FLUSH PRIVILEGES;
这步必须做! 不然授权不生效。
查看和撤销权限
查看用户权限
SHOW GRANTS FOR 'myuser'@'localhost';
撤销权限
REVOKE ALL PRIVILEGES ON mydb.* FROM 'myuser'@'localhost';
删除用户
DROP USER 'myuser'@'localhost';
常见坑
坑1:创建了用户但没授权
用户登录上了,但什么都做不了。
原因: 只创建了用户,没授权。
解决: 创建用户后一定要 GRANT。
坑2:改了密码不生效
改完密码还是旧密码能登。
原因: 没 FLUSH PRIVILEGES。
解决: 执行 FLUSH PRIVILEGES;
坑3:远程连接不上
本地能登,远程连不上。
原因: 用户只允许localhost登录。
解决: 创建 '用户'@'%' 的远程用户,或者授权。
坑4:密码太简单报错
创建用户时报密码不符合策略。
原因: MySQL 5.6以后有密码强度校验。
解决: 用复杂点的密码,或者关掉密码校验。
坑5:MySQL 8.0密码加密方式变了
老客户端连不上MySQL 8.0。
原因: MySQL 8.0默认用caching_sha2_password,老客户端不支持。
解决: 创建用户时指定老的加密方式:
CREATE USER 'myuser'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';
完整一键脚本
-- 登录MySQL后执行
CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'myuser'@'localhost' IDENTIFIED BY '你的密码';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;
总结
三步走:
- 建库
CREATE DATABASE - 建用户
CREATE USER - 授权
GRANT+FLUSH PRIVILEGES
记住: 授权完一定要刷新!
遇到问题加QQ23979811 协助处理
MySQL大表分页越查越慢,优化方案
前言
大表分页查询,第一页很快,第十页就慢,第一百页直接卡死。这是MySQL分页的经典问题,本文讲怎么优化。
为什么越往后越慢
普通分页:
SELECT * FROM orders ORDER BY id LIMIT 100000, 10;
MySQL 会先扫描前100010条,然后丢掉前100000条,只返回最后10条。
越往后翻,扫描的行越多,当然越慢。
优化方案一:子查询优化
先查出起始位置的id,再用id做条件:
SELECT * FROM orders
WHERE id >= (SELECT id FROM orders ORDER BY id LIMIT 100000, 1)
LIMIT 10;
原理: 子查询走索引,只查id列,很快。然后外层用id直接定位,不用扫那么多行。
优化方案二:游标分页(推荐)
记住上一页最后一条的id,下次从这个id之后查:
-- 第一页
SELECT * FROM orders ORDER BY id LIMIT 10;
-- 第二页(假设上一页最后id是100)
SELECT * FROM orders WHERE id > 100 ORDER BY id LIMIT 10;
-- 第三页(假设上一页最后id是110)
SELECT * FROM orders WHERE id > 110 ORDER BY id LIMIT 10;
优点: 不管翻到第几页,都是直接定位,速度一样快。
缺点: 不能跳页,只能上一页下一页。
优化方案三:覆盖索引
只查需要的列,不要 SELECT *:
SELECT id, title, create_time FROM orders ORDER BY id LIMIT 100000, 10;
如果查询的列都在索引里,MySQL直接从索引返回数据,不用回表,快很多。
优化方案四:业务上限制深分页
根本解决: 不让用户翻到那么深。
- 搜索结果只显示前100页
- 用条件过滤,不要全表翻
- 用搜索引擎(ES)代替深分页
常见坑
坑1:用了offset就一定慢
其实offset小的时候(比如前10页),差别不大。
结论: 数据量不大的时候,普通分页就行,不用过度优化。
坑2:游标分页不能用排序
游标分页只能按主键或唯一索引排序。
解决: 如果按其他字段排序,先查出对应的id列表,再用id定位。
坑3:子查询效率也不高
子查询在MySQL 5.6以前有优化器问题。
解决: MySQL 5.6以后子查询优化得很好了,放心用。
坑4:没加where条件
深分页没加where,全表扫描。
解决: 尽量加上时间范围、状态等过滤条件。
性能对比
| 方案 | 第1页 | 第100页 | 第1000页 |
|---|---|---|---|
| 普通分页 | 快 | 慢 | 很慢 |
| 子查询优化 | 快 | 中 | 慢 |
| 游标分页 | 快 | 快 | 快 |
| 搜索引擎 | 快 | 快 | 快 |
总结
大表分页优化三板斧:
- 小数据量:普通分页就行
- 中等数据量:子查询优化
- 大数据量:游标分页 + 搜索引擎
记住: 深分页不是MySQL擅长的事,数据量大了就上ES。
遇到问题加QQ23979811 协助处理
MySQL数据库导入sql文件报错解决
前言
导入SQL文件到MySQL,经常报各种错。本文总结最常见的导入报错和解决方法。
常用导入命令
mysql -u root -p 数据库名 < xxx.sql
或者登录MySQL后:
source /路径/xxx.sql;
常见报错及解决
报错1:Unknown database
ERROR 1049 (42000): Unknown database 'xxx'
原因: 数据库不存在。
解决: 先创建数据库:
CREATE DATABASE xxx DEFAULT CHARSET utf8mb4;
然后再导入。
报错2:Access denied
ERROR 1044 (42000): Access denied for user
原因: 用户没权限。
解决: 用root用户导入,或者给用户授权。
报错3:File not found
ERROR 1045 (28000): Access denied
或者文件找不到。
原因: 文件路径不对,或者文件权限不对。
解决:
- 确认文件存在:
ls -l /路径/xxx.sql - 确认文件可读:
chmod 644 /路径/xxx.sql - 用绝对路径,别用相对路径
报错4:Table already exists
ERROR 1050 (42S01): Table 'xxx' already exists
原因: 表已经存在了。
解决: 两种方法:
- 先删表再导入:
DROP TABLE xxx; - SQL文件里加
DROP TABLE IF EXISTS xxx;
报错5:Duplicate entry
ERROR 1062 (23000): Duplicate entry 'xxx' for key
原因: 主键重复。
解决:
- 先清空表再导入
- 或者用
INSERT IGNORE跳过重复
报错6:字符集乱码
导入后中文变成乱码。
原因: 字符集不对。
解决: 导入前设置字符集:
SET NAMES utf8mb4;
source /路径/xxx.sql;
或者命令行指定:
mysql -u root -p --default-character-set=utf8mb4 数据库名 < xxx.sql
报错7:max_allowed_packet太小
ERROR 2006 (HY000): MySQL server has gone away
原因: SQL文件太大,MySQL接收不了。
解决: 修改my.cnf,加大max_allowed_packet:
[mysqld]
max_allowed_packet = 64M
重启MySQL生效。
导入大文件技巧
方法1:分卷压缩
把大SQL文件拆成小的:
split -b 10M xxx.sql small_
然后逐个导入。
方法2:跳过外键检查
导入时临时关闭外键检查,更快:
SET FOREIGN_KEY_CHECKS = 0;
source /路径/xxx.sql;
SET FOREIGN_KEY_CHECKS = 1;
常见坑
坑1:用错用户名密码
导入时一直提示密码错误。
解决: 确认用户名密码,或者用 mysql -u root -p 交互式输入密码。
坑2:SQL文件不是UTF-8编码
导入后中文乱码。
解决: 用 file 命令查看文件编码:
file -i xxx.sql
坑3:没选对数据库
导入后数据不知道导到哪去了。
解决: 命令行一定要指定数据库名,或者先 USE 数据库名;
总结
导入SQL文件三步走:
- 先确认数据库存在
- 用正确的字符集导入
- 大文件就调大max_allowed_packet
记住: 报错信息一定要看清楚,别瞎试。
遇到问题加QQ23979811 协助处理
MySQL忘记root密码重置(Linux环境)
前言
忘记MySQL root密码是常见问题,不用慌,本文教你一步步重置。
重置步骤
第一步:停止MySQL服务
systemctl stop mysqld
第二步:以跳过权限模式启动
mysqld_safe --skip-grant-tables &
或者用这个方式:
systemctl set-environment MYSQLD_OPTS="--skip-grant-tables"
systemctl start mysqld
第三步:无密码登录MySQL
mysql -u root
现在不需要密码就能直接进了。
第四步:修改密码
-- 刷新权限
FLUSH PRIVILEGES;
-- 修改密码(MySQL 5.7)
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';
-- 如果上面不行,用这个
UPDATE mysql.user SET authentication_string=PASSWORD('你的新密码') WHERE User='root' AND Host='localhost';
-- 刷新权限
FLUSH PRIVILEGES;
第五步:退出,正常重启MySQL
exit
systemctl stop mysqld
systemctl start mysqld
第六步:用新密码登录测试
mysql -u root -p
输入新密码,能进去就成功了。
常见坑
坑1:MySQL 8.0和5.7语法不一样
MySQL 8.0 不能用 PASSWORD() 函数了。
解决: 用 ALTER USER 语句。
坑2:skip-grant-tables没生效
启动后还是要密码。
原因: 可能MySQL已经在跑了,新启动的没生效。
解决: 先彻底停掉MySQL:
systemctl stop mysqld
pkill -9 mysqld
再重新启动。
坑3:改完密码忘记FLUSH PRIVILEGES
改完密码直接退出,结果还是不能用新密码登录。
解决: 改完密码一定要执行 FLUSH PRIVILEGES;
坑4:远程登录还是不行
本地改完密码,远程连接还是连不上。
原因: root用户只允许本地登录。
解决: 需要单独授权远程登录:
CREATE USER 'root'@'%' IDENTIFIED BY '密码';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
总结
六步重置root密码:
- 停MySQL
- 跳过权限启动
- 无密码登录
- 改密码
- 正常重启
- 测试登录
记住: 改完密码一定要 FLUSH PRIVILEGES;
遇到问题加QQ23979811 协助处理
MySQL 事务隔离级别
MySQL 事务隔离级别
事务隔离是数据库的重要概念,搞懂4种级别很有必要。
1. 事务的ACID
- 原子性(Atomicity): 要么全成功,要么全失败
- 一致性(Consistency): 事务前后数据一致
- 隔离性(Isolation): 多个事务互不影响
- 持久性(Durability): 提交后永久保存
2. 4种隔离级别
1)读未提交(Read Uncommitted)
- 能读到未提交的数据
- 有脏读、不可重复读、幻读问题
- 性能最好
2)读提交(Read Committed)
- 只能读到已提交的数据
- 解决脏读
- 有不可重复读、幻读问题
- Oracle默认级别
3)可重复读(Repeatable Read)
- 同一个事务里读多次结果一样
- 解决脏读、不可重复读
- 有幻读问题
- MySQL默认级别
4)串行化(Serializable)
- 事务排队执行
- 解决所有问题
- 性能最差
3. 三种问题
脏读:
- 读到另一个事务未提交的数据
- 对方回滚了,你读的就是脏数据
不可重复读:
- 同一个事务里,两次读同一行结果不一样
- 中间被其他事务修改了
幻读:
- 同一个事务里,两次查询行数不一样
- 中间被其他事务插入了
4. 查看和设置
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
5. 实际使用
- 一般用默认的可重复读就够了
- 对一致性要求高的用串行化
- 不要随便改隔离级别
总结
MySQL事务隔离级别要点:
- 读未提交:性能最好,问题最多
- 读提交:解决脏读
- 可重复读:MySQL默认,解决不可重复读
- 串行化:最安全,性能最差
- 理解脏读、不可重复读、幻读
做数据库开发,事务隔离一定要懂。
Redis 常用数据类型
Redis 常用数据类型
Redis 不只是简单的 key-value,有5种常用数据类型,每种适合不同场景。
1. String(字符串)
最基础的类型,存字符串、数字都可以。
# 设置
set name "张三"
# 获取
get name
# 自增
incr age
# 设置过期时间
set token "abc" ex 3600
适用场景: 缓存、计数器、Session。
2. Hash(哈希)
存对象,比如用户信息。
# 设置单个字段
hset user:1 name "张三"
# 获取单个字段
hget user:1 name
# 设置多个字段
hmset user:1 name "张三" age 20 city "北京"
# 获取所有字段
hgetall user:1
适用场景: 存储对象(用户信息、商品信息)。
3. List(列表)
有序列表,可以做消息队列。
# 左侧添加
lpush list "a" "b" "c"
# 右侧添加
rpush list "d"
# 左侧弹出
lpop list
# 查看范围
lrange list 0 -1
适用场景: 消息队列、最新列表。
4. Set(集合)
无序,不重复,做去重。
# 添加
sadd set "a" "b" "c"
# 查看所有
smembers set
# 判断是否存在
sismember set "a"
# 交集
sinter set1 set2
适用场景: 去重、共同好友、标签。
5. ZSet(有序集合)
有序,带分数排序。
# 添加
zadd rank 100 "张三" 90 "李四" 80 "王五"
# 查看排名(从高到低)
zrevrank rank "张三"
# 查看分数
zscore rank "张三"
# 查看排行榜
zrevrange rank 0 9
适用场景: 排行榜、分数排序。
总结
Redis 5种数据类型:
- String:缓存、计数器
- Hash:存对象
- List:消息队列
- Set:去重、标签
- ZSet:排行榜
根据场景选对数据类型,用起来才高效。
PHP 字符串处理函数
PHP 字符串处理函数
字符串处理是 PHP 最常用的操作,这些函数一定要会。
1. 截取字符串
// 截取前n个字符
substr("hello world", 0, 5); // hello
// 中文截取(用mb_substr)
mb_substr("你好世界", 0, 2, "utf-8"); // 你好
2. 替换字符串
// str_replace 替换
str_replace("world", "PHP", "hello world"); // hello PHP
// 只替换第一次出现
str_replace("a", "b", "aaa", $count);
3. 查找字符串
// 查找位置(找不到返回false)
strpos("hello world", "world"); // 6
// 注意:用 === 0 判断开头
if (strpos($str, "hello") === 0) {
echo "以hello开头";
}
4. 大小写转换
// 转小写
strtolower("Hello"); // hello
// 转大写
strtoupper("hello"); // HELLO
// 首字母大写
ucfirst("hello"); // Hello
// 每个单词首字母大写
ucwords("hello world"); // Hello World
5. 去除空白
// 去除两边空格
trim(" hello "); // hello
// 去左边
ltrim(" hello "); // hello
// 去右边
rtrim(" hello "); // hello
6. 字符串拼接
// 用点拼接
$str = "hello" . " " . "world";
// 多变量拼接
$a = "hello";
$b = "world";
$c = "$a $b"; // hello world
7. 分割和合并
// 分割成数组
$arr = explode(",", "a,b,c"); // ["a", "b", "c"]
// 数组合并成字符串
$str = implode(",", $arr); // a,b,c
8. 常用技巧
1)判断是否包含字符串:
if (strpos($str, "hello") !== false) {
echo "包含hello";
}
2)反转字符串:
strrev("hello"); // olleh
3)字符串长度:
strlen("hello"); // 5
mb_strlen("你好", "utf-8"); // 2
总结
PHP 字符串处理要点:
- substr 截取,注意中文用 mb_substr
- str_replace 替换
- strpos 查找,用 !== false 判断
- trim 去空格
- explode/implode 分割合并
- 注意中文编码问题,用 mb 开头的函数
写 PHP,字符串函数天天用。
MySQL 索引优化技巧
MySQL 索引优化技巧
索引是数据库性能的关键,用对了查询快很多。
1. 索引类型
- 主键索引: 主键自带,唯一且非空
- 普通索引: 最基本的索引
- 唯一索引: 字段值不能重复
- 联合索引: 多个字段组成的索引
- 全文索引: 全文搜索用
2. 创建索引
-- 普通索引
CREATE INDEX idx_name ON users(name);
-- 唯一索引
CREATE UNIQUE INDEX idx_phone ON users(phone);
-- 联合索引
CREATE INDEX idx_name_age ON users(name, age);
3. 索引失效情况
1)不要在索引字段上做运算:
-- 失效
SELECT * FROM users WHERE age + 1 = 20;
-- 生效
SELECT * FROM users WHERE age = 19;
2)like 左模糊:
-- 失效
SELECT * FROM users WHERE name LIKE '%张';
-- 生效
SELECT * FROM users WHERE name LIKE '张%';
3)联合索引不满足最左前缀:
-- 索引:(name, age)
-- 生效(从name开始)
SELECT * FROM users WHERE name = '张三' AND age = 20;
-- 失效(跳过name直接查age)
SELECT * FROM users WHERE age = 20;
4)用 or 连接:
- or 两边有一个没索引就全表扫描
4. 优化原则
- 频繁查询的字段加索引
- 区分度高的字段适合做索引
- 不要加太多索引(影响写入性能)
- 联合索引注意最左前缀
- 尽量扩展索引,不要新建索引
5. 查看索引
-- 查看表的索引
SHOW INDEX FROM users;
6. 常见问题
- 索引加了还是慢?检查是不是失效了
- 查询还是慢?用 EXPLAIN 分析
- 写入慢?索引太多了
总结
MySQL 索引优化要点:
- 常用查询字段加索引
- 注意索引失效情况
- 联合索引最左前缀
- 不要加太多索引
- EXPLAIN 分析执行计划
数据库性能优化,索引是第一步。
Linux 文件权限详解
Linux 文件权限详解
Linux 权限是基础,搞不懂经常出问题。
1. 查看权限
ls -l
输出:
-rw-r--r-- 1 root root 1000 Oct 8 10:00 test.txt
2. 权限含义
第一位:文件类型
-
- 普通文件
- d 目录
- l 软链接
后面9位:分3组
- 第1组:所有者权限
- 第2组:所属组权限
- 第3组:其他人权限
3个字母:
- r 读(4)
- w 写(2)
- x 执行(1)
比如 rw-r--r--:
- 所有者:读写(6)
- 组:只读(4)
- 其他人:只读(4)
3. 修改权限 chmod
数字方式:
# 所有者读写执行,组读执行,其他人读执行
chmod 755 test.sh
# 所有人只读
chmod 444 test.txt
字母方式:
# 给所有者加执行权限
chmod u+x test.sh
# 给组加写权限
chmod g+w test.txt
# 去掉其他人的读权限
chmod o-r test.txt
4. 修改所有者 chown
# 修改所有者
chown www:www test.txt
# 递归修改目录
chown -R www:www /www/wwwroot
5. 常用权限
- 目录:755(所有者读写执行,其他人读执行)
- 普通文件:644(所有者读写,其他人只读)
- 脚本文件:755
6. 常见问题
1)网站打不开:
- 检查目录权限是不是 755
- 检查文件权限是不是 644
- 检查所有者是不是 www
2)上传不了文件:
- 检查目录有没有写权限
3)脚本执行不了:
- 检查有没有执行权限
总结
Linux 文件权限要点:
- r=4, w=2, x=1
- chmod 修改权限
- chown 修改所有者
- 目录 755,文件 644
- 权限不对经常出问题
做运维,权限一定要搞懂。
Nginx 负载均衡配置
Nginx 负载均衡配置
多台服务器分流,提高网站并发能力,Nginx 负载均衡很常用。
1. 什么是负载均衡
- 多台服务器做同样的服务
- Nginx 把请求分发给不同服务器
- 提高并发能力,一台挂了其他还能用
2. 基础配置
upstream myserver {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://myserver;
}
}
3. 常用分发策略
1)轮询(默认)
- 一个接一个轮流分
upstream myserver { server 127.0.0.1:8080; server 127.0.0.1:8081; }
2)加权轮询
- 性能好的服务器多分点
upstream myserver { server 127.0.0.1:8080 weight=3; server 127.0.0.1:8081 weight=1; }
3)ip_hash
- 同一个IP固定访问同一台
upstream myserver { ip_hash; server 127.0.0.1:8080; server 127.0.0.1:8081; }
4. 健康检查
upstream myserver {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
}
- max_fails:失败几次标记为挂掉
- fail_timeout:多久后重试
5. 常用参数
upstream myserver {
# 备用服务器,其他都挂了才用
server 127.0.0.1:8080 backup;
# 不参与负载均衡
server 127.0.0.1:8081 down;
}
6. 注意事项
- 多台服务器数据要同步(Session、数据库)
- Session 共享用 Redis
- 文件上传用共享存储
总结
Nginx 负载均衡要点:
- upstream 定义服务器组
- proxy_pass 转发到组
- 轮询、加权、ip_hash 策略
- 健康检查自动剔除挂掉的服务
- 注意 Session 共享
做大并发网站,负载均衡是必备的。
PHP 常用设计模式
PHP 常用设计模式
设计模式是写好代码的经验总结,常用的几种要掌握。
1. 单例模式
整个项目只有一个实例,比如数据库连接。
class Db
{
private static $instance = null;
private function __construct() {}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
$db = Db::getInstance();
2. 工厂模式
根据参数创建不同的对象。
class Factory
{
public static function make($type)
{
$class = ucfirst($type);
return new $class();
}
}
$user = Factory::make('user');
$order = Factory::make('order');
3. 观察者模式
一个对象状态变化,通知所有观察者。
interface Observer
{
public function update($event);
}
class Event
{
private $observers = [];
public function add(Observer $observer)
{
$this->observers[] = $observer;
}
public function trigger($event)
{
foreach ($this->observers as $ob) {
$ob->update($event);
}
}
}
4. 常用场景
- 单例: 数据库、日志、配置
- 工厂: 创建不同类的对象
- 观察者: 事件触发、消息通知
- 策略: 不同支付方式
- 适配器: 兼容不同接口
5. 设计原则
- 单一职责:一个类只做一件事
- 开闭原则:对扩展开放,对修改关闭
- 依赖倒置:依赖抽象不依赖具体
总结
PHP 常用设计模式要点:
- 单例模式:只创建一个实例
- 工厂模式:统一创建对象
- 观察者:事件通知
- 理解设计原则
- 不要为了模式而模式
设计模式是工具,解决问题才是目的。
Redis 缓存穿透解决
Redis 缓存穿透解决
缓存穿透是指查询不存在的数据,请求都打到数据库,可能被攻击。
1. 什么是缓存穿透
- 缓存里没有这个数据
- 数据库里也没有
- 每次请求都查数据库
- 有人恶意攻击数据库就挂了
2. 和其他问题的区别
- 穿透: 查不存在的数据
- 击穿: 热点key过期
- 雪崩: 大量key同时过期
3. 解决方案
方案一:缓存空值
function getUser($id) {
global $redis, $db;
$key = "user:".$id;
$user = $redis->get($key);
if ($user !== false) {
return json_decode($user, true);
}
// 查数据库
$user = $db->query("SELECT * FROM users WHERE id=$id");
if ($user) {
// 存正常数据
$redis->setex($key, 3600, json_encode($user));
} else {
// 存空值,短时间过期
$redis->setex($key, 60, "null");
}
return $user;
}
方案二:布隆过滤器
- 所有存在的数据存在布隆过滤器里
- 查询前先过布隆过滤器
- 不存在直接返回,不查数据库
方案三:接口校验
- 前端做参数校验
- 比如id必须大于0
- 不合法的直接拒绝
4. 代码示例
// 简单防穿透
if ($id <= 0) {
return null;
}
// 先查缓存
$user = $redis->get("user:".$id);
if ($user === "null") {
return null;
}
if ($user) {
return json_decode($user, true);
}
// 查数据库
$user = $db->query("SELECT * FROM users WHERE id=$id");
// 存缓存
if ($user) {
$redis->setex("user:".$id, 3600, json_encode($user));
} else {
$redis->setex("user:".$id, 60, "null");
}
return $user;
5. 最佳实践
- 空值缓存,短时间过期
- 重要接口加布隆过滤器
- 前端做参数校验
- 数据库做限流保护
总结
缓存穿透解决要点:
- 查不到也存空值
- 空值过期时间短
- 用布隆过滤器
- 做好接口校验
高并发系统,缓存穿透一定要防。
Linux 防火墙配置详解
Linux 防火墙配置详解
服务器安全第一步就是防火墙,学会配置很重要。
1. firewalld(CentOS 7+)
查看状态:
systemctl status firewalld
开启/关闭:
# 开启
systemctl start firewalld
# 关闭
systemctl stop firewalld
# 开机自启
systemctl enable firewalld
2. 开放端口
开放单个端口:
firewall-cmd --zone=public --add-port=80/tcp --permanent
开放多个端口:
firewall-cmd --zone=public --add-port=80-90/tcp --permanent
重新加载生效:
firewall-cmd --reload
3. 查看端口
# 查看所有开放端口
firewall-cmd --list-ports
# 查看某个端口是否开放
firewall-cmd --query-port=80/tcp
4. 关闭端口
firewall-cmd --zone=public --remove-port=80/tcp --permanent
firewall-cmd --reload
5. iptables(旧版)
查看规则:
iptables -L -n
开放端口:
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
保存规则:
service iptables save
6. 常用端口
# 常用端口
22 SSH
80 HTTP
443 HTTPS
3306 MySQL
6379 Redis
8080 Tomcat
7. 常见问题
1)端口开了还是访问不了:
- 检查云服务商安全组
- 检查服务器内部防火墙
2)远程连接不上:
- 检查 22 端口是否开放
- 检查 sshd 是否启动
总结
Linux 防火墙要点:
- firewalld 管理端口
- --permanent 永久生效
- --reload 重新加载
- 记得开放安全组
- 常用端口按需开放
做运维,防火墙是基本功。
PHP Composer 使用指南
PHP Composer 使用指南
Composer 是 PHP 的依赖管理工具,做开发必备。
1. 安装 Composer
# 下载安装
curl -sS https://getcomposer.org/installer | php
# 移动到全局
mv composer.phar /usr/local/bin/composer
# 验证
composer -V
2. 国内镜像加速
# 阿里镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
3. 常用命令
1)初始化项目:
composer init
2)安装依赖:
# 安装所有依赖
composer install
# 安装指定包
composer require monolog/monolog
# 安装开发依赖
composer require --dev phpunit/phpunit
3)更新依赖:
# 更新所有依赖
composer update
# 更新指定包
composer update monolog/monolog
4)删除依赖:
composer remove monolog/monolog
4. composer.json 说明
{
"name": "test/project",
"description": "测试项目",
"require": {
"php": ">=7.0",
"monolog/monolog": "^2.0"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
5. 自动加载
// 引入自动加载
require __DIR__ . '/vendor/autoload.php';
// 使用类
$log = new Monolog\Logger('name');
6. 常用操作
composer install:根据 lock 文件安装composer update:更新依赖composer dump-autoload:重新生成自动加载
总结
Composer 使用要点:
- 安装 Composer
- 配置国内镜像
- require 安装依赖
- autoload 自动加载
- install/update 管理依赖
做 PHP 开发,Composer 一定要会用。
MySQL 慢查询优化实战
MySQL 慢查询优化实战
数据库慢查询是性能瓶颈的常见原因,学会优化很重要。
1. 开启慢查询日志
-- 查看是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 开启慢查询
SET GLOBAL slow_query_log = ON;
-- 设置慢查询时间(秒)
SET GLOBAL long_query_time = 1;
2. 分析慢查询
用 EXPLAIN 分析:
EXPLAIN SELECT * FROM users WHERE name = '张三';
重点看:
- type:访问类型,ALL 是全表扫描,要优化
- key:用了哪个索引
- rows:扫描行数
3. 常见优化方法
1)加索引:
-- 加索引
ALTER TABLE users ADD INDEX idx_name(name);
*2)避免 SELECT :**
-- 不好
SELECT * FROM users;
-- 好
SELECT id, name FROM users;
3)避免在索引字段上做运算:
-- 不好
SELECT * FROM users WHERE YEAR(create_time) = 2026;
-- 好
SELECT * FROM users WHERE create_time >= '2026-01-01' AND create_time < '2027-01-01';
4)避免 LIKE 左模糊:
-- 不好(用不到索引)
SELECT * FROM users WHERE name LIKE '%张%';
-- 好
SELECT * FROM users WHERE name LIKE '张%';
4. 分页优化
-- 不好(大偏移量慢)
SELECT * FROM users LIMIT 100000, 10;
-- 好(用子查询)
SELECT * FROM users WHERE id >= (
SELECT id FROM users LIMIT 100000, 1
) LIMIT 10;
5. 常见慢查询原因
- 没加索引
- 索引失效
- 关联查询太多
- 数据量太大
- 大表分页
总结
MySQL 慢查询优化要点:
- 开启慢查询日志
- 用 EXPLAIN 分析
- 合理加索引
- 避免全表扫描
- 优化分页查询
数据库优化是个细活,多分析多测试。
Nginx 日志分析技巧
Nginx 日志分析技巧
Nginx 日志是排查问题的重要工具,学会分析日志很重要。
1. 日志位置
默认日志路径:
# 访问日志
/var/log/nginx/access.log
# 错误日志
/var/log/nginx/error.log
2. 日志格式
默认日志格式:
log_format access '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
3. 常用分析命令
1)查看访问量最多的IP:
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head 10
2)查看访问最多的页面:
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head 10
3)查看状态码分布:
awk '{print $9}' access.log | sort | uniq -c | sort -nr
4)查看404错误:
awk '$9 == 404 {print $7}' access.log | sort | uniq -c | sort -nr
4. 排查常用
1)查看哪个IP访问频繁:
grep "127.0.0.1" access.log
2)查看某个时间段日志:
grep "08/Oct/2026:07" access.log
3)查看错误日志:
tail -f error.log
5. 日志切割
用 logrotate 自动切割:
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
notifempty
create 0640 nginx adm
postrotate
systemctl reload nginx
endscript
}
6. 常用场景
- 被攻击了:查访问量最多的IP
- 页面报错:查404/500
- 流量突增:查访问最多的页面
- 爬虫多:查 User-Agent
总结
Nginx 日志分析要点:
- 访问日志查访问情况
- 错误日志排查问题
- awk 统计数据
- 日志自动切割
- 定期分析日志
做运维,看日志是基本功。
Git 常用命令大全
Git 常用命令大全
Git 是开发必备工具,这些常用命令一定要会。
1. 初始化和克隆
# 初始化仓库
git init
# 克隆远程仓库
git clone https://github.com/user/repo.git
2. 提交代码
# 查看状态
git status
# 添加所有文件到暂存区
git add .
# 添加指定文件
git add index.html
# 提交到本地仓库
git commit -m "提交说明"
# 提交并添加所有修改
git commit -am "提交说明"
3. 远程操作
# 推送到远程分支
git push origin master
# 拉取远程更新
git pull origin master
# 查看远程仓库
git remote -v
4. 分支操作
# 查看所有分支
git branch
# 创建新分支
git branch dev
# 切换分支
git checkout dev
# 创建并切换分支
git checkout -b dev
# 合并分支
git merge dev
# 删除分支
git branch -d dev
5. 版本回退
# 查看提交历史
git log
# 查看简化日志
git log --oneline
# 回退到上一个版本
git reset --hard HEAD^
# 回退到指定版本
git reset --hard 版本号
# 查看操作记录
git reflog
6. 撤销操作
# 撤销工作区修改
git checkout -- 文件
# 撤销暂存区
git reset HEAD 文件
# 删除文件
git rm 文件
7. 常用技巧
1)查看差异:
git diff
2)暂存修改:
# 临时保存
git stash
# 恢复暂存
git stash pop
3)打标签:
git tag v1.0
git push origin v1.0
8. 配置用户信息
# 全局配置
git config --global user.name "用户名"
git config --global user.email "邮箱"
总结
Git 常用命令要点:
- add 添加文件
- commit 提交代码
- push 推送到远程
- pull 拉取更新
- branch 分支管理
- log 查看历史
- reset 版本回退
做开发,Git 一定要熟练用。