《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。
文章目录
- 一、本文面试题目录
-
-
- 1. MySQL中的事务是什么?如何使用?
- 2. MySQL中如何设置和修改用户密码?
- 3. 如何在MySQL中创建新用户并授予权限?
- 4. 什么是视图(View)?如何在MySQL中创建和使用视图?
- 5. MySQL中的存储过程是什么?如何创建?
- 6. 如何在MySQL中调用存储过程或函数?
- 7. 触发器(Trigger)的作用是什么?如何创建触发器?
- 8. MySQL中的事件调度器(Event Scheduler)是什么?
- 9. 如何查看当前MySQL服务器的状态信息?
- 10. MySQL的复制(Replication)功能是如何工作的?
- 11. 如何配置MySQL主从复制?
- 12. MySQL中的读写分离是什么意思?如何实现?
- 13. 如何对MySQL数据库进行备份?
- 14. MySQL中的日志文件有哪些类型?各自的作用是什么?
- 15. 如何调整MySQL的配置以提高性能?
- 16. MySQL中的查询缓存(Query Cache)是什么?如何启用?
- 17. 在MySQL中如何使用全文索引(Full-Text Indexing)?
- 18. MySQL支持哪些不同的字符集和排序规则?
- 19. 如何在MySQL中执行批量插入?
- 20. MySQL中的临时表(Temporary Table)是什么?
-
一、本文面试题目录
1. MySQL中的事务是什么?如何使用?
答案:
事务是一组原子性的SQL操作,要么全部执行成功,要么全部失败,用于保证数据一致性。MySQL中事务需满足ACID特性(原子性、一致性、隔离性、持久性)。
使用方式:
默认情况下,MySQL的InnoDB引擎支持事务,且自动提交(AUTOCOMMIT=1
)。可通过以下语句手动控制事务:
-- 关闭自动提交
SET autocommit = 0;
-- 开始事务(可选,关闭自动提交后默认开启)
START TRANSACTION;
-- 执行SQL操作
INSERT INTO users (name) VALUES ('Alice');
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
-- 提交事务(所有操作生效)
COMMIT;
-- 若出错,回滚事务(所有操作撤销)
ROLLBACK;
原理:InnoDB通过 undo log(回滚日志)实现事务回滚,通过 redo log(重做日志)保证崩溃后的数据恢复,通过锁机制和MVCC(多版本并发控制)实现隔离性。
2. MySQL中如何设置和修改用户密码?
答案:
MySQL提供多种方式修改用户密码,需注意不同版本的语法差异(MySQL 5.7及以上推荐ALTER USER
)。
示例代码:
-- MySQL 5.7及以上推荐方式
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';
-- 旧版本兼容方式(需有UPDATE权限)
UPDATE mysql.user SET authentication_string = PASSWORD('new_password')
WHERE User = 'username' AND Host = 'host';
FLUSH PRIVILEGES; -- 刷新权限
-- 登录时修改当前用户密码
SET PASSWORD = 'new_password';
注意:PASSWORD()
函数在MySQL 8.0中已移除,需直接使用明文密码(内部自动加密)。密码应包含大小写字母、数字和特殊字符,增强安全性。
3. 如何在MySQL中创建新用户并授予权限?
答案:
创建用户需指定用户名、允许访问的主机(host
),并通过GRANT
语句分配权限,权限粒度可细化到库、表甚至列。
示例代码:
-- 创建用户(允许从本地访问)
CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'user_password';
-- 创建允许远程访问的用户(指定IP或%表示所有IP)
CREATE USER 'remote_user'@'192.168.1.%' IDENTIFIED BY 'secure_pass';
-- 授予权限:所有库的所有表的全部权限(谨慎使用)
GRANT ALL PRIVILEGES ON *.* TO 'new_user'@'localhost' WITH GRANT OPTION;
-- 授予指定库表的权限(SELECT、INSERT、UPDATE)
GRANT SELECT, INSERT, UPDATE ON mydb.orders TO 'remote_user'@'192.168.1.%';
-- 刷新权限使配置生效
FLUSH PRIVILEGES;
原理:用户信息存储在mysql.user
表,权限信息存储在mysql.db
、mysql.tables_priv
等系统表中,FLUSH PRIVILEGES
会重新加载这些表到内存。
4. 什么是视图(View)?如何在MySQL中创建和使用视图?
答案:
视图是虚拟表,基于SQL查询结果创建,不存储实际数据,仅保存查询逻辑,用于简化复杂查询、限制数据访问范围。
示例代码:
-- 创建视图(查询用户及其订单数量)
CREATE VIEW user_order_stats AS
SELECT u.id, u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;
-- 使用视图(像表一样查询)
SELECT * FROM user_order_stats WHERE order_count > 5;
-- 修改视图
ALTER VIEW user_order_stats AS
SELECT u.id, u.name, COUNT(o.id) AS order_count, SUM(o.amount) AS total_amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;
-- 删除视图
DROP VIEW IF EXISTS user_order_stats;
注意:视图可用于SELECT
,但INSERT/UPDATE/DELETE
受限于原表结构和视图定义,复杂视图可能不支持写入操作。
5. MySQL中的存储过程是什么?如何创建?
答案:
存储过程是预编译的SQL语句集合,可封装复杂逻辑,通过调用名称执行,减少网络传输并提高安全性。
示例代码:
-- 创建存储过程(查询指定用户的订单总数)
DELIMITER // -- 修改分隔符,避免与SQL语句中的分号冲突
CREATE PROCEDURE GetUserOrderCount(IN user_id INT, OUT order_count INT)
BEGIN
SELECT COUNT(*) INTO order_count FROM orders WHERE user_id = user_id;
END //
DELIMITER ; -- 恢复分隔符
-- 调用存储过程
CALL GetUserOrderCount(1, @count);
SELECT @count AS order_count;
优势:代码复用、减少网络交互、权限控制(可授予调用权而不暴露表权限)。
6. 如何在MySQL中调用存储过程或函数?
答案:
存储过程通过CALL
调用,函数可直接在SQL语句中使用(需有返回值)。
示例代码:
-- 调用带参数的存储过程
CALL GetUserOrderCount(1, @count); -- 输入参数1,输出参数@count
-- 创建函数(计算订单总金额)
DELIMITER //
CREATE FUNCTION CalculateOrderTotal(order_id INT)
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
DECLARE total DECIMAL(10,2);
SELECT SUM(price * quantity) INTO total FROM order_items WHERE order_id = order_id;
RETURN total;
END //
DELIMITER ;
-- 调用函数(直接用于SQL语句)
SELECT order_id, CalculateOrderTotal(order_id) AS total FROM orders;
区别:存储过程可无返回值,支持输出参数;函数必须有返回值,可嵌入SQL语句中。
7. 触发器(Trigger)的作用是什么?如何创建触发器?
答案:
触发器是与表关联的自动执行的SQL语句,用于在INSERT/UPDATE/DELETE
操作前后触发逻辑(如数据校验、日志记录)。
示例代码:
-- 创建触发器(订单插入后更新用户订单数)
DELIMITER //
CREATE TRIGGER AfterOrderInsert
AFTER INSERT ON orders
FOR EACH ROW -- 行级触发器,每插入一行执行一次
BEGIN
UPDATE users SET order_count = order_count + 1 WHERE id = NEW.user_id; -- NEW表示新插入的行
END //
DELIMITER ;
-- 创建更新前的触发器(校验价格不能为负)
DELIMITER //
CREATE TRIGGER BeforeProductUpdate
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
IF NEW.price < 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '价格不能为负数';
END IF;
END //
DELIMITER ;
-- 删除触发器
DROP TRIGGER IF EXISTS AfterOrderInsert;
注意:触发器中避免执行耗时操作,可能影响主操作性能;OLD
关键字用于UPDATE/DELETE
中表示原数据。
8. MySQL中的事件调度器(Event Scheduler)是什么?
答案:
事件调度器用于按计划自动执行SQL任务(类似定时任务),可替代外部 cron 作业,适合数据库内部定期操作(如数据清理、统计生成)。
示例代码:
-- 开启事件调度器(默认可能关闭)
SET GLOBAL event_scheduler = ON;
-- 创建事件(每天凌晨3点删除30天前的日志)
DELIMITER //
CREATE EVENT PurgeOldLogs
ON SCHEDULE EVERY 1 DAY
STARTS '2023-01-01 03:00:00'
DO
BEGIN
DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
END //
DELIMITER ;
-- 查看事件
SHOW EVENTS;
-- 禁用/启用事件
ALTER EVENT PurgeOldLogs DISABLE;
ALTER EVENT PurgeOldLogs ENABLE;
调度类型:支持AT
(一次性)、EVERY
(周期性),可指定开始和结束时间。
9. 如何查看当前MySQL服务器的状态信息?
答案:
通过SHOW
命令或系统表查看服务器状态,包括连接数、查询量、缓存使用等关键指标。
示例代码:
-- 查看服务器状态变量(如连接数、查询数)
SHOW GLOBAL STATUS; -- 全局状态
SHOW SESSION STATUS; -- 当前会话状态
-- 查看关键指标(如活跃连接数、慢查询数)
SHOW GLOBAL STATUS LIKE 'Threads_connected'; -- 当前连接数
SHOW GLOBAL STATUS LIKE 'Queries'; -- 总查询数
SHOW GLOBAL STATUS LIKE 'Slow_queries'; -- 慢查询数
-- 查看服务器变量配置
SHOW GLOBAL VARIABLES LIKE 'max_connections'; -- 最大连接数
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; -- InnoDB缓冲池大小
-- 查看存储引擎状态
SHOW ENGINE INNODB STATUS; -- InnoDB详细状态(锁、事务等)
应用:通过监控Threads_running
(运行中线程数)判断负载,Innodb_buffer_pool_reads
(物理读)评估缓存效率。
10. MySQL的复制(Replication)功能是如何工作的?
答案:
MySQL复制通过将主库(Master)的binlog(二进制日志)传输到从库(Slave)并执行,实现数据同步,支持读写分离和容灾。
工作流程:
- 主库:将所有数据修改操作记录到binlog(通过
log_bin
启用)。 - 从库:启动I/O线程连接主库,获取binlog并写入本地relay log(中继日志)。
- 从库:SQL线程读取relay log,重放操作以同步数据。
核心组件:
- binlog:主库记录变更的日志(格式可选STATEMENT/ROW/MIXED)。
- relay log:从库暂存binlog的日志。
- 复制用户:主库上授权从库连接的用户(需
REPLICATION SLAVE
权限)。
示例配置(主库):
# my.cnf
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = mydb # 仅记录指定库(可选)
11. 如何配置MySQL主从复制?
答案:
配置步骤包括主库准备、从库连接主库并同步初始数据。
示例步骤:
主库配置:
-- 创建复制用户 CREATE USER 'repl_user'@'slave_ip' IDENTIFIED BY 'repl_pass'; GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'slave_ip'; -- 锁定主库(避免备份时数据变更) FLUSH TABLES WITH READ LOCK; -- 记录当前binlog位置(文件名和偏移量) SHOW MASTER STATUS; -- 输出示例:File = mysql-bin.000001, Position = 154
从库配置:
# my.cnf server-id = 2 relay_log = /var/log/mysql/mysql-relay-bin.log
从库连接主库:
-- 配置主库信息 CHANGE MASTER TO MASTER_HOST = 'master_ip', MASTER_USER = 'repl_user', MASTER_PASSWORD = 'repl_pass', MASTER_LOG_FILE = 'mysql-bin.000001', -- 主库SHOW MASTER STATUS的File MASTER_LOG_POS = 154; -- 主库SHOW MASTER STATUS的Position -- 启动复制 START SLAVE; -- 检查状态(确保Slave_IO_Running和Slave_SQL_Running均为Yes) SHOW SLAVE STATUS\G
解锁主库:
UNLOCK TABLES;
12. MySQL中的读写分离是什么意思?如何实现?
答案:
读写分离指将读操作分配到从库,写操作保留在主库,以减轻主库压力并提高查询性能(基于主从复制)。
实现方式:
应用层分离:在代码中判断SQL类型,读操作连接从库,写操作连接主库。
# 伪代码示例 def execute_sql(sql): if sql.strip().upper().startswith(('SELECT', 'SHOW')): conn = get_slave_connection() # 读从库 else: conn = get_master_connection() # 写主库 return conn.execute(sql)
中间件分离:使用Proxy(如MySQL Proxy、MyCat、ProxySQL)自动路由,应用无需修改代码。
- 配置示例(MyCat):通过
schema.xml
定义主从关系,rule.xml
设置路由规则。
- 配置示例(MyCat):通过
数据库层分离:MySQL 8.0引入的
read_only
参数,从库设置read_only=1
禁止写入(超级用户除外)。
注意:需处理主从延迟问题(如关键读走主库),可通过Seconds_Behind_Master
监控延迟。
13. 如何对MySQL数据库进行备份?
答案:
MySQL备份分为物理备份(文件级)和逻辑备份(SQL级),各有适用场景。
1. 逻辑备份(mysqldump):
# 备份单个库
mysqldump -u root -p mydb > mydb_backup.sql
# 备份所有库(含系统库)
mysqldump -u root -p --all-databases > all_backup.sql
# 备份表结构(不包含数据)
mysqldump -u root -p --no-data mydb > mydb_schema.sql
# 压缩备份
mysqldump -u root -p mydb | gzip > mydb_backup.sql.gz
恢复:
mysql -u root -p mydb < mydb_backup.sql
2. 物理备份(适用于大库):
- 冷备份:关闭MySQL,复制数据目录(
datadir
)。 - 热备份:使用
xtrabackup
(Percona工具)在不停止服务的情况下备份InnoDB数据。xtrabackup --user=root --password=pass --backup --target-dir=/backup/
3. 增量备份:基于binlog备份,仅记录上次全量备份后的变更。
# 备份指定时间段的binlog
mysqlbinlog --start-datetime="2023-01-01 00:00:00" --stop-datetime="2023-01-02 00:00:00" /var/log/mysql/mysql-bin.000001 > incremental_backup.sql
14. MySQL中的日志文件有哪些类型?各自的作用是什么?
答案:
MySQL日志用于记录运行状态、错误和数据变更,关键日志类型如下:
日志类型 | 作用 | 启用方式(my.cnf) |
---|---|---|
错误日志 | 记录启动、运行、关闭过程中的错误信息(如崩溃、权限问题) | log_error = /var/log/mysql/error.log |
binlog(二进制日志) | 记录所有数据修改操作(用于复制和时间点恢复) | log_bin = /var/log/mysql/binlog |
慢查询日志 | 记录执行时间超过long_query_time 的SQL(默认10秒) |
slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log |
查询日志 | 记录所有SQL请求(含读写,性能影响大,一般禁用) | general_log = 1 general_log_file = /var/log/mysql/general.log |
中继日志 | 从库复制时暂存主库binlog的日志(仅从库有) | relay_log = /var/log/mysql/relay.log |
redo log | InnoDB用于崩溃恢复的重做日志(确保已提交事务不丢失) | 自动启用,innodb_log_file_size 配置大小 |
undo log | InnoDB用于事务回滚和MVCC的回滚日志(记录数据修改前的状态) | 自动管理,存储在表空间中 |
15. 如何调整MySQL的配置以提高性能?
答案:
性能优化需结合硬件、业务场景调整my.cnf
(或my.ini
)配置,核心参数如下:
内存配置:
innodb_buffer_pool_size
:InnoDB缓存表和索引的内存池,建议设为物理内存的50%-70%(专用数据库服务器)。innodb_buffer_pool_size = 8G
key_buffer_size
:MyISAM索引缓存,若使用MyISAM表建议设为内存的10%-20%。
连接配置:
max_connections
:最大并发连接数,需大于业务峰值(默认151)。max_connections = 500
wait_timeout
:空闲连接超时时间,避免连接数耗尽(默认8小时)。wait_timeout = 300 # 5分钟
InnoDB优化:
innodb_flush_log_at_trx_commit
:控制redo log刷新策略,1
(默认,最安全,每次提交刷盘)、0
(每秒刷盘,性能好但可能丢失1秒数据)。innodb_log_buffer_size
:redo log缓冲区,大事务场景调大(默认16M)。innodb_read_io_threads
/innodb_write_io_threads
:IO线程数,多磁盘可设为8。
查询优化:
query_cache_size
:查询缓存(MySQL 8.0已移除,低版本慎用,高并发写场景无效)。sort_buffer_size
:排序缓冲区,每个连接独占,避免过大导致内存耗尽。
日志优化:
- 关闭不必要的日志(如general_log),慢查询日志按需开启。
16. MySQL中的查询缓存(Query Cache)是什么?如何启用?
答案:
查询缓存是MySQL(5.7及之前版本)用于缓存SELECT
语句结果的机制,若相同查询再次执行且数据未变更,直接返回缓存结果,减少CPU和IO消耗。
特点:
- 缓存以SQL语句为键,大小写、空格差异视为不同查询。
- 表数据发生任何修改(
INSERT/UPDATE/DELETE
),相关缓存会被清空,因此写密集型场景效率低。
启用与配置(MySQL 5.7):
# my.cnf
query_cache_type = ON # 启用查询缓存(0=禁用,1=启用,2=仅显式指定SQL_CACHE的查询)
query_cache_size = 64M # 缓存总大小
query_cache_limit = 2M # 单个查询结果的最大缓存大小(超过不缓存)
使用示例:
-- 显式指定缓存(当query_cache_type=2时生效)
SELECT SQL_CACHE * FROM users WHERE id = 1;
-- 显式禁止缓存
SELECT SQL_NO_CACHE * FROM users WHERE id = 1;
注意:MySQL 8.0已移除查询缓存(因维护成本高且不适用于高并发场景),替代方案是应用层缓存(如Redis)或优化查询本身。
17. 在MySQL中如何使用全文索引(Full-Text Indexing)?
答案:
全文索引用于高效搜索文本字段中的关键词(支持自然语言搜索),适用于CHAR
、VARCHAR
、TEXT
类型,优于LIKE '%关键词%'
(无法使用普通索引)。
使用步骤:
创建全文索引:
-- 新建表时创建 CREATE TABLE articles ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(255), content TEXT, FULLTEXT INDEX ft_idx (title, content) -- 多列联合全文索引 ); -- 已有表添加 ALTER TABLE articles ADD FULLTEXT INDEX ft_idx (title, content);
使用全文搜索:
-- 搜索包含"database"或"mysql"的记录 SELECT * FROM articles WHERE MATCH(title, content) AGAINST('database mysql' IN BOOLEAN MODE); -- 搜索必须包含"database"且不包含"oracle"的记录 SELECT * FROM articles WHERE MATCH(title, content) AGAINST('+database -oracle' IN BOOLEAN MODE); -- 自然语言搜索(默认,返回相关性排序) SELECT *, MATCH(title, content) AGAINST('mysql tutorial') AS relevance FROM articles WHERE MATCH(title, content) AGAINST('mysql tutorial' IN NATURAL LANGUAGE MODE);
限制:
- 忽略太短的词(默认4个字符以下,可通过
ft_min_word_len
调整)。 - 有_stopword_(停用词,如"the"、“a”)不参与索引。
- InnoDB和MyISAM均支持,但MyISAM不支持中文分词(需第三方插件如ngram)。
18. MySQL支持哪些不同的字符集和排序规则?
答案:
字符集决定存储的字符范围,排序规则决定字符比较方式(如大小写敏感)。
常用字符集:
- utf8:支持基本Unicode字符(3字节,不支持emoji)。
- utf8mb4:utf8的超集(4字节,支持emoji和所有Unicode字符,推荐)。
- latin1:单字节字符集,支持西欧语言。
- gbk:双字节,支持中文字符。
排序规则命名规则:
- 以字符集名开头(如
utf8mb4_
)。 ci
:不区分大小写(case insensitive),cs
:区分大小写。ai
:不区分重音(accent insensitive),as
:区分重音。
示例配置:
-- 创建库时指定字符集和排序规则
CREATE DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci; -- 不区分大小写
-- 创建表时指定
CREATE TABLE users (
name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin -- 二进制比较(区分大小写)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 查看支持的字符集和排序规则
SHOW CHARACTER SET;
SHOW COLLATION LIKE 'utf8mb4%';
最佳实践:新系统统一使用utf8mb4
和utf8mb4_unicode_ci
(支持更准确的Unicode排序)。
19. 如何在MySQL中执行批量插入?
答案:
批量插入通过单条SQL插入多条记录,减少网络交互和事务开销,提高效率。
示例代码:
-- 基本批量插入(多条值用逗号分隔)
INSERT INTO users (name, email)
VALUES
('Alice', 'alice@example.com'),
('Bob', 'bob@example.com'),
('Charlie', 'charlie@example.com');
-- 从查询结果批量插入
INSERT INTO user_archives (id, name, archive_time)
SELECT id, name, NOW() FROM users WHERE last_login < '2023-01-01';
-- 批量插入优化(调整参数)
-- 1. 关闭自动提交
SET autocommit = 0;
-- 2. 执行批量插入
INSERT INTO large_table (col1, col2) VALUES (...), (...), ...;
-- 3. 手动提交
COMMIT;
优化建议:
- 单次插入行数控制在1000-5000行(避免SQL过长导致内存问题)。
- 禁用索引(临时):
ALTER TABLE table DISABLE KEYS;
,插入后启用:ENABLE KEYS;
(仅MyISAM有效,InnoDB可忽略)。 - 使用
LOAD DATA INFILE
(比INSERT
更快,适合大批量数据):LOAD DATA INFILE '/tmp/users.csv' INTO TABLE users FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (name, email);
20. MySQL中的临时表(Temporary Table)是什么?
答案:
临时表是会话级别的表,仅在当前连接可见,连接关闭后自动删除,用于存储中间结果(如复杂查询的临时数据)。
特点:
- 与普通表同名时,临时表优先被访问。
- 支持索引、触发器,但不支持外键。
- InnoDB临时表存储在内存或磁盘(超过内存阈值时),MyISAM临时表始终在磁盘。
示例代码:
-- 创建临时表
CREATE TEMPORARY TABLE temp_orders (
order_id INT,
total_amount DECIMAL(10,2)
);
-- 插入数据
INSERT INTO temp_orders
SELECT id, SUM(price * quantity) FROM order_items GROUP BY id;
-- 使用临时表
SELECT o.user_id, t.total_amount
FROM orders o
JOIN temp_orders t ON o.id = t.order_id;
-- 手动删除(可选,连接关闭自动删除)
DROP TEMPORARY TABLE IF EXISTS temp_orders;
适用场景:
- 复杂查询中分步处理数据(如多阶段统计)。
- 存储会话私有数据(避免多用户冲突)。
- 替代子查询(提高可读性和性能)。