MySQL 核心知识整理【一】

一、MySQL存储引擎对比:InnoDB vs MyISAM

在使用MySQL时,选择合适的存储引擎对性能影响很大。最常见的两个引擎是 InnoDB 和 MyISAM,它们各自的设计目标不同,适用场景也不一样。

事务与数据安全性方面 ,InnoDB 支持事务处理,支持 COMMITROLLBACK,适合电商、金融等要求数据一致性的场景。而 MyISAM 不支持事务,一旦写入错误无法回滚,更适合读多写少的业务。

外键约束方面,InnoDB 支持外键,可以定义表之间的约束,保证数据的完整性。MyISAM 不支持外键,所有的约束需要在应用层控制。

锁机制方面,InnoDB 支持行级锁和表锁,行锁可以大幅提高并发性能。MyISAM 只支持表锁,多个操作不能并发修改,容易造成阻塞。

全文索引方面,MyISAM 支持全文索引,适合文档类或搜索类应用。而 InnoDB 直到 MySQL 5.6 之后才开始支持全文索引。

适用建议:InnoDB 更适合高并发、大数据量、需要事务保障的场景,比如订单系统、交易系统。MyISAM 更适合读多写少、不涉及事务的查询系统,比如日志分析或CMS后台。

选择时需根据业务特性决定,不能单凭"速度快"或"支持事务"去判断哪个更好。



二、如何防止 SQL 注入

SQL 注入是应用程序中非常常见且危险的安全漏洞之一,攻击者可以通过构造恶意 SQL 语句,获取、篡改甚至删除数据库中的数据。避免这类问题的关键在于:不要直接拼接 SQL 语句,而是使用参数化方式传递变量

以 Java 为例,使用 PreparedStatement 可以自动对输入进行转义,防止用户注入非法语句。正确的写法是:

java 复制代码
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();

而不是:

java 复制代码
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

后者非常危险,一旦输入类似 admin' OR '1'='1,整个逻辑就会被绕过。

在使用 MyBatis 等框架时,正确方式是使用 #{} 进行参数绑定,如:

xml 复制代码
<select id="getUser" resultType="User">
  SELECT * FROM users WHERE username = #{username}
</select>

不要使用 ${},因为它会将参数直接拼接进 SQL。

核心原则是:变量永远不要直接写进 SQL 字符串里。无论使用什么语言或框架,都应该寻找它们所提供的"安全插值"机制。这不仅能提升代码可读性,也能极大增强应用的安全性。



三、怎样实现幂等

幂等,是指一个操作无论执行多少次,结果都保持一致 ,不会产生副作用。在后端开发中非常常见,尤其是涉及支付、下单、接口请求等场景。如果没有幂等保护,重复提交可能导致数据重复写入、订单重复创建等严重问题。

常见的幂等实现方式有以下三种:

1. 唯一索引(主键约束)

通过数据库的主键或唯一索引约束,来保证数据只写入一次。比如订单号、请求流水号等字段设置为唯一,一旦第二次写入相同数据,数据库会直接抛出异常。适用于插入类操作。

sql 复制代码
CREATE UNIQUE INDEX idx_order_sn ON orders(order_sn);

只要每次提交的订单号唯一,系统就能准确拒绝重复订单。

2. 乐观锁(版本号)

在更新数据时引入 version 字段,每次更新时要求版本号匹配,如果版本不一致则拒绝操作。这种方式适合控制并发更新,确保每次修改都基于上一次的结果。

sql 复制代码
UPDATE product SET stock = stock - 1, version = version + 1 WHERE id = 1 AND version = 2;

3. Token机制 + Redis

客户端发起操作前,先从服务端获取一个唯一 token,执行操作时必须携带该 token,并通过 Redis 设置 token 的一次性消费规则。一旦被使用,就立即从 Redis 中删除,后续请求再带同样的 token 就会被拦截。

这种方式适合防止重复点击、重复提交等场景,特别是在高并发请求中非常有效。



四、一条 SQL 语句的执行流程

MySQL 执行一条 SQL 查询语句,背后其实是一个完整的流程,涉及多个组件协同工作。主要可以分为两层:Server 层存储引擎层

1. 建立连接

客户端连接 MySQL,连接器首先验证用户名和密码,并加载该用户的权限信息。连接成功后才能继续发送 SQL 请求。

2. 查询缓存(MySQL 8.0 已移除)

曾经 MySQL 会先查缓存,如果完全相同的语句执行过,就直接返回缓存结果,跳过后续步骤。但由于命中率低、维护成本高,MySQL 8.0 起已移除该功能。

3. 语法解析和语义分析

SQL 语句会先交给 解析器。这个阶段会检查 SQL 是否拼写正确、语法是否合法,确认涉及的表、字段是否存在。还会将 SQL 转换为内部的数据结构,便于后续处理。

4. 查询优化

经过语义分析的 SQL,会交给 优化器。优化器的任务是选择最佳的执行计划,比如判断用哪个索引、使用何种连接方式(如 nested loop、hash join)。最终目标是尽可能提高执行效率。

5. 权限检查

执行器在执行语句前,会再次验证当前用户是否有权限对相关表或字段进行操作。如果权限不足,直接返回错误。

6. 调用存储引擎执行

执行器将最终的执行计划交给对应的存储引擎(如 InnoDB)来完成具体的数据操作,并返回结果给客户端。


相关推荐
进击的CJR29 分钟前
MySQL 8.0 OCP 英文题库解析(十)
mysql·adb·开闭原则
观测云1 小时前
HikariCP 可观测性最佳实践
数据库
文牧之1 小时前
PostgreSQL的扩展 dblink
运维·数据库·postgresql
趁你还年轻_1 小时前
Redis-旁路缓存策略详解
数据库·redis·缓存
在云上(oncloudai)2 小时前
AWS DocumentDB vs MongoDB:数据库的技术抉择
数据库·mongodb·aws
夕泠爱吃糖2 小时前
MySQL范式和反范式
数据库·mysql
Re2753 小时前
并发事务问题:现象、成因与解决方案
mysql
时序数据说4 小时前
时序数据库IoTDB与EdgeX Foundry集成适配服务介绍
大数据·数据库·开源·时序数据库·iotdb
用手手打人4 小时前
SpringBoot(七) --- Redis基础
数据库·redis·缓存
Despacito0o4 小时前
瀚文机械键盘固件开发详解:HWKeyboard.cpp文件解析与应用
数据库·mongodb·计算机外设