适用人群:运维工程师、后端开发、云服务器使用者、Linux初学者
前言
MySQL 5.7 已于 2023 年 10 月结束生命周期(EOL),MySQL 8.0 也将于 2026 年 4 月迎来 EOL。作为长期支持版本(LTS),MySQL 8.4 是生产环境升级的首选。
本文采用通用二进制包(Generic Linux Tarball) 方式部署,相比 yum 安装具有以下优势:
- 无需编译,部署快速
- 不依赖系统包管理器(yum/apt),避免版本冲突
- 可灵活控制安装路径与权限
- 易于实现多实例部署
前置要求 :一台 CentOS 7 服务器。如果还没有,请参考:VMware安装centos教程
一、安装MySQL规范
1.1 MySQL安装方式
本次采用二进制安装 (Generic Binary Tarball)。MySQL 通用二进制发行版以 .tar.xz 压缩文件形式提供,适用于多种 Linux 平台。与源码编译安装、yum、rpm 等方式相比,二进制安装兼具灵活性与便捷性。
1.2 MySQL运行用户
MySQL 进程使用专用虚拟用户运行,该用户不允许登录、不创建家目录:
bash
# 切换到root用户
useradd -s /sbin/nologin -M mysql
-s /sbin/nologin:禁止登录;-M:不创建家目录
1.3 MySQL目录规范
| 目录类型 | 路径 | 说明 |
|---|---|---|
| 下载目录 | /server/tools |
存放安装包 |
| 系统目录 | /opt/mysql/mysql-xx.xx |
MySQL 主程序 |
| 软连接 | /usr/local/mysql |
指向 /opt/mysql/mysql-xx.xx |
| 数据目录 | /data/mysql/mysql+port/{data,logs} |
数据和日志 |
| 配置文件 | /data/mysql/mysql+port/my+port.cnf |
实例配置文件 |
1.4 确定libc版本
MySQL 8.4 要求 glibc >= 2.17。检查方法:
bash
[root@test ~]# ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
如果版本低于 2.17,安装过程会报错,需要先升级 glibc。
1.5 MySQL下载
通过网盘分享的文件:mysql-8.4.10-linux-glibc2.17-x86_64 链接: https://pan.baidu.com/s/1_cWyRzLmgmV2KDpAdyqQzg?pwd=s7v1 提取码: s7v1 --来自百度网盘的分享
二、二进制安装MySQL
2.1 创建MySQL虚拟用户
bash
useradd -s /sbin/nologin -M mysql

2.2 创建目录
bash
mkdir -p /server/tools
mkdir -p /opt/mysql
mkdir -p /data/mysql/mysql3306/{data,logs}
cd /server/tools

2.3 上传二进制包
bash
rz


如果没有 rz 工具,先安装:
bash
yum install -y lrzsz
2.4 解压二进制包
bash
tar xf mysql-8.4.10-linux-glibc2.17-x86_64.tar.xz

2.5 将软件部分移动到指定目录
bash
mv mysql-8.4.10-linux-glibc2.17-x86_64 /opt/mysql/mysql-8.4.10

2.6 创建软连接
bash
ln -s /opt/mysql/mysql-8.4.10/ /usr/local/mysql

2.7 删除mariadb
CentOS 7 默认预装了 mariadb-libs,与 MySQL 冲突,需先卸载:
bash
rpm -e --nodeps mariadb-libs

2.8 配置文件整理
bash
vim /data/mysql/mysql3306/my3306.cnf
写入以下配置:
ini
[mysqld]
user=mysql
basedir=/usr/local/mysql
datadir=/data/mysql/mysql3306/data
socket=/data/mysql/mysql3306/mysql.sock
server_id=1
port=3306
log_error=/data/mysql/mysql3306/logs/error.log
log_bin=/data/mysql/mysql3306/logs/mysql-bin
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=true
log_slave_updates=1
max_connections=1024
wait_timeout=60
sort_buffer_size=2M
max_allowed_packet=32M
join_buffer_size=2M
innodb_buffer_pool_size=128M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_log_files_in_group=2
binlog_cache_size=2M
max_binlog_cache_size=8M
max_binlog_size=512M
expire_logs_days=7
slow_query_log=on
slow_query_log_file=/data/mysql/mysql3306/logs/slow.log
long_query_time=0.5
log_queries_not_using_indexes=1

配置说明:
innodb_buffer_pool_size:InnoDB 缓冲池大小,生产环境建议设置为物理内存的 70% 左右gtid_mode=on:启用 GTID,便于主从复制管理binlog_format=row:行级二进制日志,推荐生产环境使用slow_query_log:开启慢查询日志,便于性能调优
2.9 安装MySQL依赖包
bash
yum install libaio-devel -y
yum install numactl -y


MySQL 依赖
libaio库,如果未安装,数据目录初始化和后续启动将失败。
2.10 更改MySQL相关目录的用户组
bash
chown -R mysql:mysql /data/*

2.11 初始化数据库
使用 --initialize-insecure 初始化(root 密码为空):
bash
/usr/local/mysql/bin/mysqld --defaults-file=/data/mysql/mysql3306/my3306.cnf --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql/mysql3306/data

两种初始化方式对比:
--initialize-insecure:root 密码为空,需后续手动设置--initialize:自动生成随机 root 密码,密码保存在 error.log 中
2.12 加入环境变量
bash
vim /etc/profile
# 在文件末尾添加
PATH="/usr/local/mysql/bin:$PATH"
source /etc/profile

2.13 启动MySQL
bash
mysqld --defaults-file=/data/mysql/mysql3306/my3306.cnf &
2.14 查看是否启动成功
bash
netstat -lntup | grep mysql

三、常见MySQL启动失败案例
3.1 目录权限问题
问题描述 :[ERROR] Could not open file '/data/mysql/mysql3306/logs/error.log' for error logging: Permission denied
原因 :数据目录的用户和用户组不是 mysql:mysql
解决:
bash
chown -R mysql:mysql /data/*
3.2 参数问题
问题描述 :[ERROR] unknown variable 'basedi=/usr/local/mysql'
原因:配置文件中参数拼写错误或参数因版本不再支持
解决 :检查 my3306.cnf,修正错误参数
3.3 配置文件加载错误
问题描述:启动时未加载到正确的配置文件
解决 :启动时务必通过 --defaults-file 指定正确的配置文件路径
bash
mysqld --verbose --help | grep defaults
3.4 端口被占用
问题描述 :[ERROR] Do you already have another mysqld server running on port: 3306 ?
原因:端口 3306 已被占用(多实例场景下端口冲突)
解决 :检查并终止占用端口的进程,或修改配置文件中的 port 参数
3.5 手工删除二进制文件
问题描述 :[ERROR] Failed to open log (file '/data/mysql/mysql3306/logs/mysql-bin.000014', errno 2)
原因 :二进制日志文件被手动删除,但 mysql-bin.index 中仍有记录
解决 :编辑 mysql-bin.index,删除对应的二进制日志文件记录
3.6 修改共享表空间参数大小
问题描述 :[ERROR] InnoDB: The Auto-extending innodb_system data file './ibdata1' is of a different size
原因 :修改了 innodb_data_file_path 参数,但现有 ibdata1 文件大小不匹配
解决 :在初始化数据库之前设置 innodb_data_file_path 大小,重新修改配置文件中的值,必须小于或等于默认值(12M)
四、MySQL启动失败排查方法
- 明确当前 MySQL 的版本、启动方式及配置文件
- 查看错误日志文件 :
/data/mysql/mysql3306/logs/error.log
错误日志是排查启动问题的第一手资料,记录了 MySQL 启动、关闭及运行时的所有错误信息。
五、连接MySQL数据库的方式
5.1 本地连接(通过 socket)
bash
mysql -uroot -p -S /data/mysql/mysql3306/mysql.sock

5.2 远程连接(通过 TCP/IP)
bash
mysql -uroot -p -P3306 -h192.168.58.51
六、MySQL数据库用户安全策略
6.1 初始化方式对比
| 初始化参数 | root密码 | 密码位置 |
|---|---|---|
--initialize-insecure |
空 | 无需查找 |
--initialize |
随机生成 | error.log |
使用 --initialize 初始化:
bash
/usr/local/mysql/bin/mysqld --defaults-file=/data/mysql/mysql3306/my3306.cnf --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql/mysql3306/data
查看生成的密码:
bash
grep 'temporary password' /data/mysql/mysql3306/logs/error.log
6.2 修改密码
方法一:ALTER USER
sql
ALTER USER root@'localhost' IDENTIFIED BY '123456';
方法二:mysqladmin
bash
mysqladmin -uroot -p123456 password '123' -S /data/mysql/mysql3306/mysql.sock
七、MySQL SQL语言全面解析
SQL(Structured Query Language)是操作关系型数据库的标准语言。根据功能,SQL 语句主要分为四大类。
7.1 DDL(数据定义语言)
DDL 用于定义数据库对象(数据库、表、字段、索引等)。
7.1.1 数据库操作
sql
-- 查询所有数据库
SHOW DATABASES;
-- 查询当前数据库
SELECT DATABASE();
-- 创建数据库
CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 删除数据库
DROP DATABASE IF EXISTS mydb;
-- 切换数据库
USE mydb;
7.1.2 表操作
sql
-- 创建表
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
email VARCHAR(100) NOT NULL COMMENT '邮箱',
age TINYINT UNSIGNED COMMENT '年龄',
status TINYINT DEFAULT 1 COMMENT '状态:1-正常,0-禁用',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 查看所有表
SHOW TABLES;
-- 查看表结构
DESC users;
-- 或
SHOW CREATE TABLE users;
-- 修改表:添加列
ALTER TABLE users ADD COLUMN phone VARCHAR(20) COMMENT '手机号';
-- 修改表:修改列
ALTER TABLE users MODIFY COLUMN age INT COMMENT '年龄';
-- 修改表:重命名列
ALTER TABLE users CHANGE COLUMN status user_status TINYINT DEFAULT 1;
-- 修改表:删除列
ALTER TABLE users DROP COLUMN phone;
-- 重命名表
RENAME TABLE users TO user_accounts;
-- 删除表
DROP TABLE IF EXISTS user_accounts;
7.2 DML(数据操作语言)
DML 用于对数据库表中的数据进行增、删、改操作。
7.2.1 INSERT(插入数据)
sql
-- 插入单条数据
INSERT INTO users (username, email, age) VALUES ('zhangsan', 'zhangsan@example.com', 25);
-- 插入多条数据
INSERT INTO users (username, email, age) VALUES
('lisi', 'lisi@example.com', 30),
('wangwu', 'wangwu@example.com', 28);
-- 插入数据(省略列名,需按顺序提供所有值)
INSERT INTO users VALUES (NULL, 'zhaoliu', 'zhaoliu@example.com', 32, 1, NOW(), NOW());
-- 从另一张表插入数据
INSERT INTO users_backup SELECT * FROM users WHERE age > 30;
7.2.2 UPDATE(更新数据)
sql
-- 更新单条记录
UPDATE users SET age = 26 WHERE username = 'zhangsan';
-- 更新多条记录
UPDATE users SET status = 0 WHERE age > 30;
-- 更新时使用表达式
UPDATE users SET age = age + 1 WHERE age < 18;
-- 注意:不带 WHERE 条件会更新所有记录!
-- UPDATE users SET status = 0; -- 危险操作!
7.2.3 DELETE(删除数据)
sql
-- 删除指定记录
DELETE FROM users WHERE username = 'zhangsan';
-- 删除所有记录(保留表结构)
DELETE FROM users;
-- 快速清空表(重置自增ID,释放存储空间)
TRUNCATE TABLE users;
-- 注意:不带 WHERE 条件会删除所有记录!
-- DELETE FROM users; -- 危险操作!
7.3 DQL(数据查询语言)
DQL 用于查询数据库表中的记录,是业务中使用频次最高的 SQL 类型。
7.3.1 基础查询
sql
-- 查询所有字段
SELECT * FROM users;
-- 查询指定字段
SELECT id, username, email FROM users;
-- 查询并去重
SELECT DISTINCT age FROM users;
-- 查询时使用别名
SELECT username AS 用户名, email AS 邮箱 FROM users;
7.3.2 条件查询(WHERE)
sql
-- 比较运算符
SELECT * FROM users WHERE age > 25;
SELECT * FROM users WHERE age >= 18 AND age <= 30;
SELECT * FROM users WHERE age BETWEEN 18 AND 30;
SELECT * FROM users WHERE username = 'zhangsan';
SELECT * FROM users WHERE username != 'zhangsan';
-- 逻辑运算符
SELECT * FROM users WHERE age > 25 AND status = 1;
SELECT * FROM users WHERE age < 18 OR age > 60;
-- 模糊查询(LIKE)
SELECT * FROM users WHERE username LIKE 'zhang%'; -- 以zhang开头
SELECT * FROM users WHERE username LIKE '%san'; -- 以san结尾
SELECT * FROM users WHERE username LIKE '%a%'; -- 包含a
-- IN 操作
SELECT * FROM users WHERE age IN (25, 30, 35);
-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE phone IS NULL;
7.3.3 排序(ORDER BY)
sql
-- 单字段排序
SELECT * FROM users ORDER BY age DESC; -- 降序
SELECT * FROM users ORDER BY age ASC; -- 升序(默认)
-- 多字段排序
SELECT * FROM users ORDER BY age DESC, created_at ASC;
7.3.4 分组与聚合(GROUP BY)
sql
-- 常用聚合函数:COUNT, SUM, AVG, MAX, MIN
SELECT COUNT(*) AS total FROM users;
SELECT AVG(age) AS avg_age FROM users;
SELECT MAX(age) AS max_age, MIN(age) AS min_age FROM users;
-- 分组统计
SELECT status, COUNT(*) AS count FROM users GROUP BY status;
-- 分组后筛选(HAVING)
SELECT status, COUNT(*) AS count
FROM users
GROUP BY status
HAVING count > 5;
7.3.5 分页查询(LIMIT)
sql
-- 查询前10条
SELECT * FROM users LIMIT 10;
-- 分页:第1页(每页10条)
SELECT * FROM users LIMIT 0, 10;
-- 第2页
SELECT * FROM users LIMIT 10, 10;
-- 第3页
SELECT * FROM users LIMIT 20, 10;
7.3.6 多表连接(JOIN)
sql
-- 内连接(INNER JOIN):只返回匹配的记录
SELECT u.username, o.order_id, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
-- 左连接(LEFT JOIN):返回左表所有记录
SELECT u.username, o.order_id, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;
-- 右连接(RIGHT JOIN):返回右表所有记录
SELECT u.username, o.order_id, o.amount
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;
-- 子查询
SELECT * FROM users WHERE age > (SELECT AVG(age) FROM users);
7.4 DCL(数据控制语言)
DCL 用于管理数据库用户和控制访问权限。
7.4.1 用户管理
sql
-- 创建用户(MySQL 8.4 要求密码使用加密方式)
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'SecurePass123!';
CREATE USER 'app_user'@'%' IDENTIFIED BY 'SecurePass123!'; -- 允许任何主机
-- 查看所有用户
SELECT user, host FROM mysql.user;
-- 修改用户密码
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'NewPass456!';
-- 删除用户
DROP USER 'app_user'@'localhost';
7.4.2 权限管理
sql
-- 授予权限(所有权限)
GRANT ALL PRIVILEGES ON mydb.* TO 'app_user'@'localhost';
-- 授予特定权限
GRANT SELECT, INSERT, UPDATE ON mydb.users TO 'app_user'@'localhost';
-- 授予只读权限
GRANT SELECT ON mydb.* TO 'readonly_user'@'%';
-- 查看用户权限
SHOW GRANTS FOR 'app_user'@'localhost';
-- 撤销权限
REVOKE INSERT, UPDATE ON mydb.users FROM 'app_user'@'localhost';
-- 刷新权限(使权限立即生效)
FLUSH PRIVILEGES;
7.4.3 角色管理(MySQL 8.0+)
sql
-- 创建角色
CREATE ROLE 'app_read_role', 'app_write_role';
-- 为角色授予权限
GRANT SELECT ON mydb.* TO 'app_read_role';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_write_role';
-- 将角色授予用户
GRANT 'app_read_role' TO 'readonly_user'@'%';
-- 设置默认角色
SET DEFAULT ROLE 'app_read_role' TO 'readonly_user'@'%';
八、MySQL数据类型
MySQL 支持多种数据类型,分为以下几大类。
8.1 数值类型
| 类型 | 字节 | 范围(有符号) | 范围(无符号) | 用途 |
|---|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 | 小整数(状态、性别) |
| SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 | 小型整数 |
| MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 | 中等整数 |
| INT | 4 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 | 标准整数 |
| BIGINT | 8 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1 | 大整数(ID、时间戳) |
| FLOAT | 4 | ±1.175E-38 ~ ±3.402E+38 | --- | 单精度浮点数 |
| DOUBLE | 8 | ±2.225E-308 ~ ±1.798E+308 | --- | 双精度浮点数 |
| DECIMAL(M,D) | 可变 | 取决于 M,D | --- | 精确小数(金额) |
8.2 字符串类型
| 类型 | 最大长度 | 说明 |
|---|---|---|
| CHAR(M) | 255 字符 | 定长字符串,效率高 |
| VARCHAR(M) | 65535 字符 | 变长字符串,节省空间 |
| TINYTEXT | 255 字符 | 短文本 |
| TEXT | 65535 字符 | 长文本 |
| MEDIUMTEXT | 16777215 字符 | 中等长度文本 |
| LONGTEXT | 4294967295 字符 | 超大文本 |
| BINARY(M) | 255 字节 | 定长二进制 |
| VARBINARY(M) | 65535 字节 | 变长二进制 |
| BLOB | 65535 字节 | 二进制大对象 |
| ENUM | 65535 个值 | 枚举类型 |
| SET | 64 个值 | 集合类型 |
8.3 日期时间类型
| 类型 | 字节 | 范围 | 格式 |
|---|---|---|---|
| DATE | 3 | 1000-01-01 ~ 9999-12-31 | YYYY-MM-DD |
| TIME | 3 | -838:59:59 ~ 838:59:59 | HH:MM:SS |
| DATETIME | 8 | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS |
| TIMESTAMP | 4 | 1970-01-01 00:00:01 ~ 2038-01-19 03:14:07 | YYYY-MM-DD HH:MM:SS |
| YEAR | 1 | 1901 ~ 2155 | YYYY |
8.4 JSON 类型
MySQL 8.0+ 原生支持 JSON 数据类型:
sql
-- 创建包含 JSON 列的表
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
attributes JSON
);
-- 插入 JSON 数据
INSERT INTO products VALUES (1, 'Laptop', '{"brand": "Dell", "ram": "16GB", "storage": "512GB"}');
-- 查询 JSON 字段
SELECT id, name, JSON_EXTRACT(attributes, '$.brand') AS brand FROM products;
-- 简写方式
SELECT id, name, attributes->>'$.brand' AS brand FROM products;
-- JSON 条件查询
SELECT * FROM products WHERE JSON_EXTRACT(attributes, '$.ram') = '16GB';
九、MySQL索引
索引用于快速查找具有特定列值的行。没有索引,MySQL 必须从第一行开始读取整个表。
9.1 索引类型
| 索引类型 | 说明 | 特点 |
|---|---|---|
| PRIMARY KEY | 主键索引 | 唯一且非空,每个表只能有一个 |
| UNIQUE | 唯一索引 | 索引列值必须唯一 |
| INDEX | 普通索引 | 允许重复值,加速查询 |
| FULLTEXT | 全文索引 | 用于全文搜索 |
| 组合索引 | 多列索引 | 遵循最左前缀原则 |
9.2 索引操作
sql
-- 创建表时指定索引
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_no VARCHAR(32) UNIQUE,
amount DECIMAL(10,2),
status TINYINT,
created_at DATETIME,
INDEX idx_user_id (user_id),
INDEX idx_status_created (status, created_at) -- 组合索引
);
-- 为已有表添加索引
CREATE INDEX idx_user_id ON orders (user_id);
CREATE UNIQUE INDEX idx_order_no ON orders (order_no);
CREATE INDEX idx_status_created ON orders (status, created_at);
-- 使用 ALTER TABLE 添加索引
ALTER TABLE orders ADD INDEX idx_amount (amount);
-- 查看索引
SHOW INDEX FROM orders;
-- 删除索引
DROP INDEX idx_user_id ON orders;
ALTER TABLE orders DROP INDEX idx_amount;
9.3 索引使用原则
- 最左前缀原则 :组合索引
(a, b, c)可有效用于a、(a,b)、(a,b,c)的查询条件 - 避免在索引列上使用函数 :
WHERE DATE(created_at) = '2026-01-01'不会使用索引 - LIKE 以 % 开头不会使用索引 :
LIKE '%abc'无法使用索引 - 选择区分度高的列:如性别(2个值)不适合建索引
- 索引不是越多越好:维护索引有开销,影响写入性能
十、MySQL事务
事务是数据库操作的最小工作单元,具有 ACID 特性。
10.1 事务的 ACID 特性
| 特性 | 说明 |
|---|---|
| 原子性(Atomicity) | 事务中的所有操作要么全部成功,要么全部失败 |
| 一致性(Consistency) | 事务执行前后,数据库状态保持一致 |
| 隔离性(Isolation) | 并发事务之间互不干扰 |
| 持久性(Durability) | 事务提交后,数据永久保存 |
10.2 事务操作
sql
-- 开启事务
START TRANSACTION;
-- 或
BEGIN;
-- 执行操作
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 提交事务(确认修改)
COMMIT;
-- 回滚事务(撤销修改)
ROLLBACK;
-- 设置自动提交(默认开启)
SET autocommit = 0; -- 关闭自动提交
SET autocommit = 1; -- 开启自动提交
10.3 事务隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✔ | ✔ | ✔ |
| READ COMMITTED | ✘ | ✔ | ✔ |
| REPEATABLE READ(默认) | ✘ | ✘ | ✔ |
| SERIALIZABLE | ✘ | ✘ | ✘ |
sql
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
10.4 保存点(Savepoint)
sql
START TRANSACTION;
INSERT INTO users (username) VALUES ('user1');
SAVEPOINT sp1;
INSERT INTO users (username) VALUES ('user2');
SAVEPOINT sp2;
-- 回滚到 sp1,user2 的插入被撤销,user1 保留
ROLLBACK TO SAVEPOINT sp1;
COMMIT;
十一、MySQL锁机制
InnoDB 存储引擎支持行级锁和表级锁,MyISAM 只支持表级锁。
11.1 锁的分类
按粒度分类
| 锁类型 | 说明 | 适用场景 |
|---|---|---|
| 表级锁 | 锁定整张表 | MyISAM、MEMORY 引擎 |
| 行级锁 | 锁定特定行 | InnoDB 引擎,高并发场景 |
| 页级锁 | 锁定数据页 | 较少使用 |
按模式分类
| 锁模式 | 说明 |
|---|---|
| 共享锁(S锁/读锁) | 允许其他事务读取,不允许修改 |
| 排他锁(X锁/写锁) | 阻止其他事务读写 |
| 意向锁 | InnoDB 自动添加的锁,用于表级与行级锁协调 |
11.2 锁操作示例
sql
-- 手动加共享锁(读锁)
START TRANSACTION;
SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE;
-- 或(MySQL 8.0+)
SELECT * FROM users WHERE id = 1 FOR SHARE;
-- 手动加排他锁(写锁)
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 执行更新操作
UPDATE users SET balance = balance - 100 WHERE id = 1;
COMMIT;
11.3 死锁
死锁是指两个或多个事务相互等待对方释放锁的情况。InnoDB 默认会自动检测死锁并回滚其中一个受影响的事务。
避免死锁的建议:
- 按相同顺序访问表和行
- 保持事务简短
- 使用较低的隔离级别
- 为表添加合适的索引,减少锁定的行数
十二、总结
本文从零开始,完整演示了在 CentOS 7 上使用通用二进制包部署 MySQL 8.4 LTS 的全过程,涵盖:
- 安装规范:用户、目录、依赖检查
- 二进制安装:从创建用户到启动服务的完整步骤
- 故障排查:6 种常见启动失败场景及解决方案
- 安全策略:密码管理、用户权限控制
- SQL 语言:DDL、DML、DQL、DCL 四大类语句的详细用法
- 数据类型:数值、字符串、日期时间、JSON 类型
- 索引:类型、操作与使用原则
- 事务与锁:ACID 特性、隔离级别、锁机制与死锁处理
MySQL 8.4 作为 LTS 版本,将为生产环境提供长期稳定的支持。掌握二进制安装和 SQL 操作是运维工程师和后端开发的核心技能,希望本文能帮助你在实际工作中高效部署和管理 MySQL 数据库。