SQL
SQL
John DoePrompt:
ddl语句是什么
Response:
DDL 是 Data Definition Language(数据定义语言) 的缩写,它是 SQL(结构化查询语言)的一部分,用于 定义或修改数据库结构,比如:数据库、表、视图、索引、约束等。
🔧 常见的 DDL 语句包括:
| 语句 | 功能说明 |
|---|---|
CREATE |
创建数据库对象(如表、数据库、视图等) |
ALTER |
修改已存在的数据库对象结构 |
DROP |
删除数据库对象(表、数据库等) |
TRUNCATE |
清空表中的所有数据(但保留表结构) |
RENAME |
重命名数据库对象 |
✅ 常用 DDL 示例:
1. 创建数据库
1 | CREATE DATABASE school; |
2. 创建数据表
1 | CREATE TABLE students ( |
3. 修改表结构(添加列)
1 | ALTER TABLE students ADD email VARCHAR(100); |
4. 删除表
1 | DROP TABLE students; |
5. 清空表数据,但保留表结构
1 | TRUNCATE TABLE students; |
🆚 DDL vs DML vs DCL 简要对比
| 类型 | 全称 | 用途 |
|---|---|---|
| DDL | Data Definition Language | 定义和修改数据库结构(表、列、索引) |
| DML | Data Manipulation Language | 操作数据(增删查改)例如 SELECT、INSERT、UPDATE、DELETE |
| DCL | Data Control Language | 控制访问权限,例如 GRANT、REVOKE |
如果你需要某个具体场景下的 DDL 语句,我可以帮你写出来——只需告诉我你希望设计的表结构或功能。
Prompt:
ddl表操作
2/2
Response:
你提到“DDL 表操作”,指的是使用 DDL(数据定义语言) 来对**数据表(Table)**进行的各种结构定义和修改操作。下面我会系统地列出:
✅ DDL 表操作总览
1. 创建表(CREATE TABLE)
1 | CREATE TABLE employees ( |
2. 修改表结构(ALTER TABLE)
➤ 添加新列:
1 | ALTER TABLE employees ADD email VARCHAR(100); |
➤ 修改列的数据类型:
1 | ALTER TABLE employees MODIFY salary DECIMAL(12, 2); |
➤ 重命名列:
(MySQL)
1 | ALTER TABLE employees CHANGE name full_name VARCHAR(150); |
➤ 删除列:
1 | ALTER TABLE employees DROP COLUMN email; |
➤ 添加主键 / 外键 / 唯一约束:
1 | -- 添加主键 |
3. 删除表(DROP TABLE)
1 | DROP TABLE employees; |
4. 清空表数据但保留结构(TRUNCATE TABLE)
1 | TRUNCATE TABLE employees; |
5. 重命名表(RENAME TABLE)
1 | RENAME TABLE employees TO staff; |
🧠 补充说明
| 操作 | 会删除数据? | 会删除表结构? | 可回滚? |
|---|---|---|---|
DROP TABLE |
✅ 是 | ✅ 是 | ❌ 不可回滚 |
TRUNCATE TABLE |
✅ 是 | ❌ 否 | ❌ 不可回滚 |
DELETE FROM(DML) |
✅ 是(可加条件) | ❌ 否 | ✅ 可回滚(需开启事务) |
如果你有某张具体的表结构或想实现的业务(比如学生成绩管理、订单管理、用户管理等),我可以帮你写出完整的 DDL 建表语句,告诉我你的需求即可。
Prompt:
创建表时常用约束有什么
Response:
创建表时,常用的 SQL 约束(Constraints) 用于限定数据的合法性,确保数据库中数据的准确性和完整性。
✅ 常用约束及作用一览
| 约束名 | 作用说明 |
|---|---|
PRIMARY KEY |
唯一标识一条记录,不允许为 NULL 且唯一 |
FOREIGN KEY |
保证两表数据之间的引用一致性(外键) |
UNIQUE |
限定某列(或组合列)值不能重复 |
NOT NULL |
强制该字段不能为 NULL |
DEFAULT |
指定字段的默认值 |
CHECK |
限定字段的值必须满足某种条件(部分数据库如 MySQL 8.0+ 才支持) |
AUTO_INCREMENT |
自动增长(通常用于主键,MySQL 专有) |
🧱 示例:创建带各种约束的表
1 | CREATE TABLE users ( |
🔍 每种约束的解释和示例
1. PRIMARY KEY
- 确保每条记录有唯一标识(主键)
1 | id INT PRIMARY KEY |
2. NOT NULL
- 强制该列不能为空
1 | username VARCHAR(50) NOT NULL |
3. UNIQUE
- 防止重复值(可用于邮箱、用户名等字段)
1 | email VARCHAR(100) UNIQUE |
4. DEFAULT
- 如果插入时未提供值,则使用默认值
1 | status VARCHAR(20) DEFAULT 'active' |
5. CHECK
- 限制字段值范围(如年龄必须 ≥ 18)
1 | age INT CHECK (age >= 18) |
⚠️ 注意:MySQL 在 8.0 之前版本对
CHECK语法支持不好,可能会被忽略。
6. FOREIGN KEY
- 创建引用另一个表的字段,确保引用数据存在
1 | FOREIGN KEY (role_id) REFERENCES roles(id) |
7. AUTO_INCREMENT
- 整数主键自动增长(MySQL 专用)
1 | id INT AUTO_INCREMENT |
🧠 小贴士:
- 每个表只能有一个主键,但可以有多个唯一约束。
- 外键约束默认会拒绝删除或更新引用表中的数据,可以加
ON DELETE/ON UPDATE条件控制行为。1
FOREIGN KEY (dept_id) REFERENCES departments(id) ON DELETE CASCADE
如你有特定业务场景(如学生管理、订单系统等),我可以帮你定制建表语句和推荐合适的约束。需要的话直接告诉我。
Prompt:
mysql数据类型
Response:
在 MySQL 中,数据类型决定了表中字段能存储什么类型的数据。它们可以分为以下几类:
📦 一、数值类型
✅ 1. 整数类型
| 类型 | 大小(字节) | 范围(有符号) | 说明 |
|---|---|---|---|
TINYINT |
1 | -128 ~ 127 | 适用于很小的整数 |
SMALLINT |
2 | -32,768 ~ 32,767 | |
MEDIUMINT |
3 | -8百万 ~ 8百万 | |
INT 或 INTEGER |
4 | -21亿 ~ 21亿 | 常用 |
BIGINT |
8 | 超过 ±9千万亿 | 适用于大数,如金额、ID |
加上
UNSIGNED关键字可使范围变为非负(从 0 开始翻倍)
例:INT UNSIGNED→ 0 ~ 42亿多
✅ 2. 小数/浮点类型
| 类型 | 说明 |
|---|---|
DECIMAL(M,D) 或 NUMERIC(M,D) |
精确小数,适用于金额。M 是总位数,D 是小数位数。例:DECIMAL(10,2) |
FLOAT(M,D) |
单精度浮点,适用于不要求精度的计算 |
DOUBLE(M,D) 或 REAL(M,D) |
双精度浮点,误差更小 |
🕒 二、日期和时间类型
| 类型 | 格式 | 说明 |
|---|---|---|
DATE |
YYYY-MM-DD | 日期 |
TIME |
HH:MM:SS | 时间 |
DATETIME |
YYYY-MM-DD HH:MM:SS | 日期+时间 |
TIMESTAMP |
同 DATETIME |
通常用于记录创建或更新时间(可自动更新) |
YEAR |
YYYY | 表示年份(如 2025) |
🔤 三、字符串类型
✅ 1. 定长与变长字符
| 类型 | 说明 |
|---|---|
CHAR(n) |
固定长度,适用于定长字段,如身份证号 |
VARCHAR(n) |
变长,最大长度 65535 字节,适合变长文本,如姓名、邮箱等 |
推荐使用
VARCHAR,节省空间。CHAR适合长度一致的场景。
✅ 2. 文本类型(适用于长文本)
| 类型 | 最大长度 | 用途 |
|---|---|---|
TINYTEXT |
255 字节 | 短文本 |
TEXT |
65KB | 普通文本,如评论 |
MEDIUMTEXT |
16MB | 较大文本 |
LONGTEXT |
4GB | 超长文本,如文章正文 |
📁 四、二进制类型(少用)
| 类型 | 用途 |
|---|---|
BINARY(n) |
定长二进制 |
VARBINARY(n) |
变长二进制 |
BLOB |
存储二进制大对象,如图片、音频等 |
🧠 小提示
- 选择合适的数据类型有利于节省存储、提高性能。
- 在金额相关场景中推荐使用
DECIMAL而不是FLOAT/DOUBLE,因为浮点数有精度问题。 VARCHAR比TEXT更高效,可以创建索引;TEXT不能直接作为索引字段(需加前缀)。
如你需要为某张表选择合适的数据类型或做设计,我可以帮你写一个建表语句或推荐字段类型。需要的话请提供表的结构或业务需求。
Prompt:
DQL语句中的聚合函数
Response:
在 DQL(Data Query Language,数据查询语言)中,聚合函数(Aggregate Functions)用于对一组数据进行计算并返回单一结果,常与 GROUP BY 搭配使用。
📊 常见聚合函数
| 函数 | 作用 | 示例 |
|---|---|---|
COUNT() |
统计行数(记录数) | COUNT(*) 统计总行数,COUNT(column) 统计非 NULL 的行数 |
SUM() |
计算总和 | SUM(salary) 计算工资总和 |
AVG() |
计算平均值 | AVG(salary) |
MAX() |
求最大值 | MAX(salary) |
MIN() |
求最小值 | MIN(salary) |
🔹 基本用法
1 | SELECT |
🔹 搭配 GROUP BY 使用
1 | -- 按部门统计员工数量和平均工资 |
🔹 搭配 HAVING 过滤分组结果
1 | -- 查询平均工资高于 5000 的部门 |
🧠 小提示
COUNT(*)会统计所有行,包括NULL值;COUNT(column)只统计该列非 NULL 的行。- 聚合函数忽略 NULL 值(
COUNT(*)除外)。 - 聚合函数通常不能直接与普通列混用,必须配合
GROUP BY。
如果你需要的话,我可以帮你整理 DQL 聚合函数 + GROUP BY + HAVING 的速查表,方便你考试或面试用。
你要我帮你做吗?
Prompt:
dql语句中where与having的区别
Response:
在 DQL(数据查询语言)中,WHERE 和 HAVING 都可以用来过滤数据,但它们作用的阶段和对象不同:
📌 核心区别
| 特性 | WHERE |
HAVING |
|---|---|---|
| 作用阶段 | 分组前 过滤 | 分组后 过滤 |
| 能否使用聚合函数 | ❌ 不能直接使用(因为此时还没计算聚合值) | ✅ 可以使用(已经有了聚合结果) |
| 过滤对象 | 行(Row) | 分组(Group) |
是否依赖 GROUP BY |
独立使用 | 一般与 GROUP BY 搭配使用(也可单独用) |
🔹 工作流程(执行顺序)
SQL 查询的大致执行顺序是:
1 | FROM → WHERE → GROUP BY → 聚合函数计算 → HAVING → SELECT → ORDER BY |
这说明:
WHERE是在分组 之前,对原始行过滤。HAVING是在分组 之后,对分组结果过滤。
🔹 示例对比
1. 使用 WHERE(分组前过滤)
1 | -- 先找出工资大于 3000 的员工,再按部门分组 |
作用:在分组前就把工资 ≤ 3000 的员工排除了。
2. 使用 HAVING(分组后过滤)
1 | -- 按部门分组,并找出平均工资大于 5000 的部门 |
作用:先把所有员工分组,计算平均工资,再过滤平均工资 ≤ 5000 的部门。
3. 两者结合
1 | -- 先过滤单个员工工资 > 3000,再找平均工资 > 5000 的部门 |
🧠 记忆口诀
WHERE 先筛行,HAVING 后筛组。
WHERE 不懂聚合,HAVING 专挑聚合。
如果你愿意,我可以帮你画一张 SQL 执行顺序流程图,把 WHERE 和 HAVING 的位置直观标出来,方便你快速理解。
你要我画吗?
Prompt:
给我一些MySQL高频面试题
Response:
好嘞,我帮你整理一份 MySQL 高频面试题清单,涵盖基础、优化、事务、锁机制、索引、SQL 编写等核心考点,并附上简要回答思路。
📌 一、基础与数据类型
- MySQL 常见数据类型有哪些?各自的适用场景?
- 整数:
TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT(ID、计数器等) - 小数:
DECIMAL(精确,适合金额)、FLOAT、DOUBLE(非精确,适合科学计算) - 字符串:
CHAR(定长)、VARCHAR(变长)、TEXT(大文本) - 日期时间:
DATE、DATETIME、TIMESTAMP、YEAR
- 整数:
CHAR与VARCHAR的区别?CHAR(n):定长,存储速度快,浪费空间;适合固定长度数据。VARCHAR(n):变长,节省空间,查询速度略慢,需额外存储长度信息。
DATETIME和TIMESTAMP的区别?DATETIME:存储范围大(1000-9999 年),不受时区影响。TIMESTAMP:存储 1970-2038 年的时间,受时区影响,常用于记录创建/更新时间。
📌 二、索引与优化
- 索引的类型有哪些?
- 主键索引(
PRIMARY KEY) - 唯一索引(
UNIQUE) - 普通索引(
INDEX) - 组合索引(多列索引)
- 全文索引(
FULLTEXT) - 空间索引(
SPATIAL)
- 主键索引(
- B+ 树索引的原理?为什么用 B+ 树而不是 B 树?
- B+ 树所有数据存储在叶子节点,叶子节点有链表,范围查询效率高;
- B 树数据可能存储在非叶节点,范围查询不如 B+ 树高效。
- 覆盖索引是什么?
- 查询结果的字段全部在索引中,不用回表。
- 优点:减少磁盘 IO,提高性能。
- 最左前缀原则
- 组合索引会按最左列优先匹配,比如
(a,b,c)索引,可用a、a,b、a,b,c但不能直接用b,c。
- 组合索引会按最左列优先匹配,比如
EXPLAIN的作用?- 查看 SQL 执行计划,包括索引使用情况、扫描行数、连接方式等。
📌 三、事务与锁
- MySQL 事务的四大特性(ACID)
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
- 事务隔离级别及问题
* 读未提交(可能脏读)
* 读已提交(可能不可重复读)
* 可重复读(可能幻读,MySQL InnoDB 通过间隙锁解决)
* 串行化(性能最差) - MySQL 有哪些锁?
* 行锁、表锁、意向锁、间隙锁(Gap Lock) - InnoDB 与 MyISAM 的区别?
* InnoDB:支持事务、行级锁、外键;适合高并发 OLTP
* MyISAM:不支持事务、表级锁、查询速度快;适合读多写少的场景
📌 四、SQL 编写与优化
WHERE和HAVING的区别?
*WHERE:分组前过滤,不能用聚合函数。
*HAVING:分组后过滤,可以用聚合函数。INNER JOIN、LEFT JOIN、RIGHT JOIN区别?
* INNER JOIN:两表匹配的记录
* LEFT JOIN:左表全部 + 匹配到的右表
* RIGHT JOIN:右表全部 + 匹配到的左表- 如何优化 SQL 查询性能?
* 建立合适的索引(避免索引失效)
* 避免SELECT *
* 分页优化(LIMIT+ 覆盖索引)
* 使用EXPLAIN分析执行计划
* 大表分区/分库分表 - 索引失效的常见情况
* 使用OR条件(部分情况)
* 列类型隐式转换
* 在索引列上使用函数
* 模糊查询%abc(前导%会失效)
📌 五、高级
- MySQL 的存储引擎有哪些?
* 常用:InnoDB、MyISAM、Memory
* 特殊:Archive(归档)、Federated(远程数据) - 主从复制原理
* 主库记录 binlog → 从库 I/O 线程读取 binlog → SQL 线程重放数据。 - 分库分表策略
* 垂直拆分(按功能模块拆表)
* 水平拆分(按 ID 范围/哈希分片) - 慢查询优化步骤
* 开启slow_query_log
* 用EXPLAIN分析
* 添加索引 / 重写 SQL / 分表
我可以帮你把这些 MySQL 高频面试题整理成 题目 + 参考答案 + 关键知识点总结 的 PDF,方便你在面试前速记。
如果你要的话,我还能帮你额外加上 SQL 执行顺序图 和 索引原理图。
你需要我帮你整理成那种面试速记版吗?
1/2
Prompt:
jdbc是什么
Response:
JDBC 全称是 Java Database Connectivity,即 Java 数据库连接,是 Java 提供的一套 操作数据库的标准 API。
它的作用就是:
让 Java 程序用统一的方式(同一套代码)去连接和操作各种不同的数据库(MySQL、Oracle、PostgreSQL、SQL Server…),而不用关心具体数据库的底层实现细节。
📌 JDBC 的核心作用
- 建立数据库连接(Java ↔ 数据库)
- 发送 SQL 语句(增删改查)
- 处理 SQL 执行结果
- 关闭数据库资源
🔹 JDBC 的工作原理
JDBC 本身是一个 接口规范,具体的数据库厂商(MySQL、Oracle 等)会提供 JDBC 驱动程序(Driver) 来实现这些接口。
执行流程是:
1 | Java 程序 → JDBC API → JDBC 驱动 → 数据库 |
🧱 常用的 JDBC 相关类
| 类/接口 | 作用 |
|---|---|
DriverManager |
管理数据库驱动,创建数据库连接 |
Connection |
表示与数据库的连接 |
Statement |
用于执行 SQL(简单语句) |
PreparedStatement |
执行预编译 SQL(防 SQL 注入) |
ResultSet |
封装查询结果集 |
🔹 JDBC 示例(连接 MySQL)
1 | import java.sql.*; |
📍 小结
- JDBC 是 Java 操作数据库的标准接口规范。
- 需要配合 数据库厂商提供的 JDBC 驱动 才能工作。
- 常用类:
DriverManager、Connection、PreparedStatement、ResultSet。 - 生产环境中,通常结合 连接池(如 Druid、HikariCP)来管理 JDBC 连接,提高性能。
如果你需要的话,我可以帮你画一个 JDBC 工作原理流程图,让你更直观地理解 Java 是怎么一步步和数据库通信的。
你想让我画吗?
Prompt:
预编译sql是什么
Response:
预编译 SQL(Prepared SQL)指的是:
在执行 SQL 时,先让数据库服务器解析、编译、优化 SQL 语句的结构(即 SQL 模板),然后在多次执行时只需要 传递参数,而不需要重复编译 SQL。
它的常见实现就是 **JDBC 的 PreparedStatement**。
📌 原理
- 编写 SQL 模板(带占位符
?) - 第一次执行时,数据库会 编译 SQL 模板 并缓存执行计划
- 后续执行时,只需要 绑定参数,直接使用缓存的执行计划,跳过重复解析
- 这样既能 提高性能,又能 防止 SQL 注入
🔹 示例
普通 SQL(Statement)
1 | String sql = "SELECT * FROM users WHERE username = '" + name + "'"; |
⚠ 缺点:
- 每次执行都要解析 SQL
- 拼接字符串容易被 SQL 注入 攻击
预编译 SQL(PreparedStatement)
1 | String sql = "SELECT * FROM users WHERE username = ?"; |
✅ 优点:
- 性能更高(编译一次,多次执行)
- 防止 SQL 注入(参数不会直接拼接到 SQL 中,而是单独传给数据库)
- 代码可读性更好
📊 预编译执行流程(JDBC)
1 | 客户端(Java程序): |
📍 总结
- 预编译 SQL 就是 先编译 SQL 结构,再绑定参数执行 的方式。
- 在 JDBC 中用
PreparedStatement实现。 - 优点:性能更高 + 防 SQL 注入。
- 适用场景:频繁执行同一类 SQL(比如批量插入、重复查询)时效果最佳。
如果你愿意,我可以帮你画一张 “预编译 SQL vs 普通 SQL” 执行流程对比图,让你秒懂它们的区别。
你要我画吗?
Prompt:
什么是mybatis
Response:
MyBatis 是一个 Java 的持久层框架,它的作用是 帮助开发者更方便地在 Java 程序中执行 SQL 语句,并且可以 自动把数据库查询结果映射成 Java 对象。
简单说:
MyBatis 让你写 SQL 更自由,同时又能自动把 SQL 和 Java 对象关联起来。
📌 MyBatis 的特点
- 半自动化 ORM 框架
- ORM(Object Relational Mapping)= 对象关系映射
- Hibernate 是全自动 ORM(帮你自动生成 SQL)
- MyBatis 是半自动 ORM(SQL 你自己写,框架帮你映射结果)
- 支持自定义 SQL
- 不像 Hibernate 那样生成 SQL,而是由你写 SQL(灵活、可控)
- SQL 与 Java 分离
- SQL 语句写在 XML 文件中或注解中,方便维护
- 自动结果映射
- 查询结果自动映射到 Java 对象(支持复杂对象映射)
- 支持动态 SQL
- 可以在 SQL 中用
<if>、<where>、<foreach>等标签实现动态拼接 SQL
- 可以在 SQL 中用
🔹 MyBatis 核心组件
| 组件 | 作用 |
|---|---|
SqlSessionFactory |
创建 SqlSession 的工厂 |
SqlSession |
执行 SQL、获取映射器、管理事务 |
Mapper(映射器) |
Java 接口与 SQL 的映射(XML/注解) |
| XML 配置文件 | 定义数据库连接、映射关系、SQL 语句等 |
🔹 MyBatis 基本使用流程
- 定义实体类
1 | public class User { |
- 定义 Mapper 接口
1 | public interface UserMapper { |
- 编写 XML 映射文件
1 | <mapper namespace="com.example.mapper.UserMapper"> |
- 加载 MyBatis 配置文件 & 执行 SQL
1 | InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); |
📍 MyBatis 的优缺点
✅ 优点
- SQL 灵活可控,性能可优化
- 映射关系清晰,支持复杂 SQL
- 易于和 Spring/Spring Boot 集成
❌ 缺点
- 需要自己写 SQL(SQL 复杂度高的项目更适合)
- SQL 与 Java 分离,调试时可能要在多个文件间切换
如果你需要的话,我可以帮你画一个 MyBatis 工作原理流程图,让你直观地理解它是怎么把 SQL 和 Java 对象关联起来的。
你要我帮你画吗?
Prompt:
在springboot项目中使用注解方式的流程呢
2/2
Response:
在 Spring Boot 项目中,使用 注解方式 来集成 MyBatis 的流程,其实就是不用 XML 写 SQL,而是直接在 Mapper 接口里用注解定义 SQL。这样代码和 SQL 写在一起,更简洁。
我给你分步骤讲清楚:
📌 Spring Boot + MyBatis 注解方式流程
1. 引入依赖
在 pom.xml 中添加 MyBatis Spring Boot Starter 和数据库驱动(以 MySQL 为例):
1 | <dependencies> |
2. 配置数据库连接
在 application.yml 或 application.properties 中配置数据源:
1 | spring: |
3. 创建实体类
1 | public class User { |
4. 创建 Mapper 接口(用注解写 SQL)
1 | import org.apache.ibatis.annotations.*; |
5. 编写 Service 层
1 | import org.springframework.stereotype.Service; |
6. 编写 Controller 层
1 | import org.springframework.web.bind.annotation.*; |
7. 启动类开启 Mapper 扫描
如果 Mapper 接口都加了 @Mapper,Spring Boot 会自动识别;
如果没加 @Mapper,可以用 @MapperScan:
1 |
|
📍 总结流程
- 引入 MyBatis + 数据库依赖
- 配置数据源
- 创建实体类
- 用
@Mapper+ 注解 SQL 定义 Mapper 接口 - 编写 Service 层调用 Mapper
- 编写 Controller 层提供 API
- 启动类加
@MapperScan(或在每个 Mapper 上加@Mapper)
如果你愿意,我可以帮你画一张 Spring Boot + MyBatis 注解方式执行流程图,把从 Controller 到 SQL 执行的过程一步步画出来,方便你面试讲解。
你要我画吗?
Prompt:
跟mybatis-plus有什么区别
Response:
Spring Boot 项目中使用 MyBatis(普通版)和 MyBatis-Plus(MP) 的区别,主要体现在 开发效率、自动化程度和功能扩展 上。下面我帮你梳理清楚:
1️⃣ MyBatis(普通版)
- 特点:
- SQL 需要自己手写(XML 或 注解)
- 映射结果需要自己配置
- 灵活、可控,但重复工作多
- 优点:
- SQL 完全由开发者控制,适合复杂查询
- 可以自定义映射关系
- 缺点:
- CRUD SQL 需要手写
- 项目中重复性高(insert、update、delete、select)
- 动态 SQL 复杂
2️⃣ MyBatis-Plus
- 特点:
- 在 MyBatis 基础上提供 增强功能
- 内置 CRUD 方法(几乎无需写 SQL)
- 支持 条件构造器(Wrapper)、分页、逻辑删除、乐观锁、自动填充字段等
- 支持 代码生成器,可自动生成 Entity、Mapper、Service、Controller
- 优点:
- 开发效率大幅提升(基本 CRUD 免写 SQL)
- 支持 Lambda 表达式查询,代码更安全、更简洁
- 提供丰富插件(分页、性能分析、乐观锁)
- 缺点:
- 对 SQL 的灵活性略低(复杂 SQL 仍需手写)
- 对新手理解 Wrapper API 可能需要适应
3️⃣ CRUD 对比示例
假设有 User 表:
| 功能 | MyBatis | MyBatis-Plus |
|---|---|---|
| 查询所有用户 | @Select("SELECT * FROM users") List<User> selectAll(); |
userMapper.selectList(null); |
| 根据 id 查询 | @Select("SELECT * FROM users WHERE id = #{id}") User selectById(int id); |
userMapper.selectById(id); |
| 插入 | @Insert("INSERT INTO users(...) VALUES(...)") int insert(User user); |
userMapper.insert(user); |
| 更新 | @Update(...) int update(User user); |
userMapper.updateById(user); |
| 删除 | @Delete(...) int delete(int id); |
userMapper.deleteById(id); |
| 分页查询 | 手写 SQL + limit | userMapper.selectPage(page, wrapper); |
4️⃣ 总结
| 方面 | MyBatis | MyBatis-Plus |
|---|---|---|
| SQL 控制 | 完全自定义 | 内置 CRUD,可自定义 SQL |
| 开发效率 | 较低 | 高(大量自动化功能) |
| 学习成本 | SQL 基础即可 | 需要学习 MP 特有 API |
| 适用场景 | SQL 复杂、灵活性要求高 | 常规 CRUD,快速开发,企业项目中常用 |
💡 总结一句话:
MyBatis 灵活可控,MyBatis-Plus 高效自动化,MP 是 MyBatis 的增强版。
如果你愿意,我可以帮你画一张 MyBatis 与 MyBatis-Plus 流程对比图,直观展示 CRUD 的差异和执行流程。
你想让我画吗?
Prompt:
什么是数据库连接池
Response:
数据库连接池(Database Connection Pool)是 管理和复用数据库连接的一种技术,目的是提升数据库操作效率,减少频繁创建和关闭连接的开销。下面我帮你详细梳理:
1️⃣ 概念
- 数据库连接:应用程序与数据库之间的通信通道,每次操作数据库都需要建立连接。
- 问题:
- 每次数据库操作都建立连接 → 性能消耗大
- 数据库同时连接数有限 → 容易资源耗尽
- 解决方案:连接池
- 事先创建一定数量的数据库连接放入池中
- 应用程序需要使用时从池中获取连接,用完再归还池中,而不是关闭
- 避免频繁创建和销毁连接,提高性能
2️⃣ 工作原理
- 初始化连接池:启动时创建固定数量的数据库连接(可配置最小、最大连接数)。
- 获取连接:应用程序向连接池申请数据库连接。
- 使用连接:应用程序执行 SQL。
- 归还连接:执行完毕将连接归还池中,不关闭连接。
- 连接池管理:
- 超时回收空闲连接
- 异常连接检测与重建
- 动态扩展或缩减连接数量
3️⃣ 优点
- 性能提升:避免频繁创建和销毁连接的开销
- 资源复用:充分利用有限的数据库连接数
- 管理方便:支持最大连接数、最小连接数、空闲检测等配置
- 提高系统稳定性:防止数据库连接耗尽
4️⃣ 常用连接池
| 连接池 | 特点 |
|---|---|
| HikariCP | 高性能,Spring Boot 默认推荐 |
| Druid | 阿里开源,监控和统计功能丰富 |
| C3P0 | 老牌连接池,功能全面,但性能一般 |
| Tomcat JDBC Pool | 与 Tomcat 集成好,配置简单 |
5️⃣ Spring Boot 中使用数据库连接池
Spring Boot 默认支持 HikariCP:
1 | spring: |
使用连接池后,开发者只需要通过
DataSource获取连接,不必手动管理连接生命周期,Spring Boot 会自动管理。
💡 总结一句话:
数据库连接池就是“连接的缓存”,提高数据库操作效率并节约资源。
如果你需要,我可以画一张 数据库连接池工作原理图,让你一眼看懂连接获取、使用、归还的流程。
你想让我画吗?
Prompt:
基于mybatis的增删改查操作
Response:
好的,我给你整理一份 基于 MyBatis 的增删改查(CRUD)操作示例,用最常见的方式(XML 映射或注解方式),假设有一张 User 表:
1 | CREATE TABLE user ( |
1️⃣ 实体类 User.java
1 | public class User { |
2️⃣ Mapper 接口 UserMapper.java
1 | import org.apache.ibatis.annotations.*; |
注解方式:方便快速开发;
XML 方式:适合复杂 SQL 和动态 SQL。
3️⃣ Mapper XML 示例(可选)
UserMapper.xml:
1 | <mapper namespace="com.example.mapper.UserMapper"> |
4️⃣ 使用示例
1 | import org.springframework.beans.factory.annotation.Autowired; |
✅ 总结:
- 插入 →
insert/@Insert - 删除 →
delete/@Delete - 更新 →
update/@Update - 查询 →
select/@Select
如果你愿意,我可以帮你再写一份 MyBatis-Plus 版本 CRUD 对比示例,让你一眼看出 MyBatis 和 MP 的差异。
你想让我写吗?
Prompt:
Mybatis#{…},${…}区别
Response:
在 MyBatis 中,#{...} 和 ${...} 经常被用在 SQL 映射里,但它们的本质和用途完全不同,理解好差异非常重要,尤其在面试中。下面我帮你详细梳理:
1️⃣ #{...} —— 预编译参数占位符
- 作用:用于 预编译 SQL,防止 SQL 注入。
- 执行原理:
- MyBatis 会将
#{参数}替换成?占位符。 - 然后通过 PreparedStatement 设置参数值。
- MyBatis 会将
- 特点:
- 自动处理 类型转换。
- 自动防止 SQL 注入。
- 适合 值类型传参。
- 示例:
1 |
|
生成的 SQL 大概是:
1 | SELECT * FROM user WHERE username = ? AND age = ? |
然后通过 PreparedStatement 设置参数值。
2️⃣ ${...} —— 字符串替换占位符
- 作用:直接将
${参数}替换成字符串 拼接到 SQL 中。 - 执行原理:
- MyBatis 在生成 SQL 时 直接做文本替换。
- 特点:
- 不会预编译,存在 SQL 注入风险。
- 常用于 动态表名、列名、排序字段。
- 不会自动处理类型。
- 示例:
1 |
|
如果传入 orderBy = "age",limit = 10,生成 SQL 为:
1 | SELECT * FROM user ORDER BY age LIMIT 10 |
3️⃣ 总结对比
| 特性 | #{...} |
${...} |
|---|---|---|
| 参数替换方式 | 预编译,占位符 ? |
字符串拼接 |
| 安全性 | 高,防 SQL 注入 | 低,容易注入 |
| 适用场景 | 值类型传参 | 表名、列名、排序等 SQL 片段 |
| 类型处理 | 自动处理 | 不处理 |
| 示例 | WHERE age = #{age} |
ORDER BY ${columnName} |
💡 面试小技巧:
- 遇到用户输入的值一定用
#{}。 - 只在 动态 SQL 或 无法用预编译处理的情况 才用
${}。
如果你想,我可以画一张 #{} vs ${} 参数传递流程图,让区别更直观。
你想让我画吗?
Prompt:
@Insert(“INSERT INTO user(username, email, age) VALUES(#{username}, #{email}, #{age})”)
@Options(useGeneratedKeys = true, keyProperty = “id”)
int insertUser(User user);这里#{username}, #{email}, #{age})是属性名还是表的字段名啊
Response:
在你给的这段 MyBatis 注解 SQL 中:
1 |
|
username、email、age在VALUES(#{...})里指的是 实体类User的属性名,不是数据库表的字段名。- MyBatis 会根据 Java Bean 的 getter/setter 获取属性值,然后把值填充到 SQL 里的占位符中(通过预编译
?)。 - SQL 左边的
user(username, email, age)才是数据库表的 字段名。
📌 对比总结:
| 位置 | 含义 |
|---|---|
user(username, email, age) |
数据库表 user 的字段名 |
#{username}, #{email}, #{age} |
Java 实体类 User 的属性名 |
所以,MyBatis 允许字段名和属性名不一致,只要在实体类属性上用 @TableField("表字段名") 或 <resultMap> 映射即可。
如果你想,我可以画一张 MyBatis 注解 SQL 属性-字段映射示意图,让这个概念更清楚。
你想让我画吗?
Prompt:
@param注解
Response:
在 MyBatis 中,@Param 注解用于 给 SQL 参数起别名,特别是在接口方法有 多个参数 时,方便在 SQL 映射中引用。下面详细讲解:
1️⃣ 基本用法
1 |
|
@Param("name"):给方法参数username起别名name。- SQL 中使用
#{name}绑定这个参数的值。 - 必须给多个参数的接口方法使用
@Param,否则 MyBatis 默认只能用#{param1},#{param2}…引用。
2️⃣ 为什么需要 @Param
场景 1:多个参数
1 | User getUserByUsernameAndEmail(String username, String email); |
- 如果不加
@Param,SQL 中需要写:
1 | SELECT * FROM user WHERE username = #{param1} AND email = #{param2} |
- 可读性差,容易出错。
场景 2:增加可读性
1 | User getUserByUsernameAndEmail( String username, String email); |
SQL 中就可以写:
1 | SELECT * FROM user WHERE username = #{username} AND email = #{email} |
- 可读性好,直观。
3️⃣ 单参数方法
- 如果接口方法 只有一个参数,通常不需要
@Param:
1 |
|
4️⃣ 总结
| 特性 | 说明 |
|---|---|
| 用途 | 给接口方法参数起别名 |
| 适用 | 多参数方法,或者为了 SQL 可读性 |
| SQL 中引用 | 用 #{别名} |
| 不用 | 单参数方法可以省略 |
💡 面试提示:
- 多参数方法 必须用
@Param或者使用 实体对象封装参数。 - 避免直接用
#{param1}、#{param2},可读性差。


