MySQL约束
MySQL 约束详解:保障数据完整性的六大机制
约束(Constraint)是 MySQL 中用于限制表中数据的规则,通过强制数据满足特定条件,确保数据库的完整性、一致性和准确性。MySQL 支持六大类约束,虽然部分约束在实现上有局限,但仍是设计可靠数据表的核心工具。
六大约束类型及作用
| 约束类型 | 作用描述 | MySQL 支持情况 |
|---|---|---|
| NOT NULL | 限制字段值不能为 NULL(必须填写)。 |
完全支持 |
| DEFAULT | 为字段设置默认值,当插入数据时未指定该字段则使用默认值。 | 完全支持 |
| PRIMARY KEY | 主键约束,唯一标识表中的每行记录,要求字段值唯一且非空。 | 完全支持(单字段或复合主键) |
| UNIQUE | 唯一约束,保证字段值在表中唯一,但允许为 NULL(NULL 可重复)。 | 完全支持 |
| CHECK | 检查约束,限制字段值必须满足指定条件(如 age > 0)。 |
MySQL 8.0.16+ 支持,低版本仅语法兼容但不生效 |
| FOREIGN KEY | 外键约束,限制两个表的关系,确保从表字段值必须来自主表的关联字段。 | 支持,但需存储引擎为 InnoDB(MyISAM 不支持) |
约束的使用方法
1. NOT NULL(非空约束)
确保字段必须有值,禁止插入 NULL。
1 | CREATE TABLE student ( |
2. DEFAULT(默认约束)
为字段设置默认值,简化插入操作(未指定字段时自动填充)。
1 | CREATE TABLE employee ( |
3. PRIMARY KEY(主键约束)
主键是表的 “唯一标识符”,具有以下特性:
springmvc处理模型数据
Spring MVC 模型数据处理详解:4 种核心方式与错误处理
在 Spring MVC 开发中,将业务数据传递到视图(如 JSP、Thymeleaf)是核心需求之一。Spring MVC 提供了 ModelAndView、Map/Model、@SessionAttributes、@ModelAttribute 四种灵活的模型数据处理方式,覆盖从 “单次请求数据传递” 到 “跨请求数据共享” 的全场景。从 “数据传递原理→使用场景→实战示例” 三个维度,彻底讲透模型数据的处理逻辑。
核心概念:模型数据的本质
Spring MVC 中的 “模型数据” 本质是 键值对(Key-Value),存储在 Model 或 ModelMap 中,最终会通过 HttpServletRequest.setAttribute() 绑定到请求域(Request Scope),视图技术(如 JSP 的 EL 表达式 ${key})可直接访问这些数据。
- 作用域分类:
- 请求域(Request Scope):数据仅在当前请求有效(默认,如 ModelAndView、Map 传递的数据);
- 会话域(Session Scope):数据在当前用户会话中有效(需通过
@SessionAttributes显式设置)
方式 1:ModelAndView —— 视图与数据的统一载体
ModelAndView 是 Spring MVC 早期最常用的模型数据处理方式,同时封装 “视图信息” 和 “模型数据”,适合需要明确指定视图且传递数据的场景。
1. 核心原理与源码解析
ModelAndView 内部维护两个核心变量,分别对应 “视图” 和 “数据”:
1 | public class ModelAndView { |
spring事务
Spring 事务深度解析:从 ACID 到分布式事务
Spring 事务是企业级应用中确保数据一致性的核心机制,基于 AOP(面向切面编程) 实现,将事务管理逻辑与业务逻辑解耦。它不仅支持本地事务(单数据库),还通过 JTA 等规范支持分布式事务(跨数据库 / 服务)。从 “事务基础→核心属性→实现原理→实战配置→分布式事务” 五个维度,系统拆解 Spring 事务的工作机制与最佳实践。
事务基础:理解 ACID 与并发问题
事务(Transaction)是数据库操作的最小单元,必须满足 ACID 特性,同时需解决并发场景下的脏读、不可重复读、幻读问题。
1. 事务的 ACID 特性
ACID 是事务的四大核心特性,确保数据操作的一致性与可靠性:
| 特性 | 英文全称 | 核心含义 | 示例场景(转账:A 转 100 给 B) |
|---|---|---|---|
| 原子性(Atomicity) | Atomicity | 事务中的操作 “要么全成功,要么全失败”,无中间状态 | A 扣款 100 成功,但 B 到账 100 失败 → 事务回滚,A 余额恢复 |
| 一致性(Consistency) | Consistency | 事务执行前后,业务状态需符合预期(数据完整性约束不被破坏) | 转账前 A+B 余额 = 2000 → 转账后仍为 2000(不会出现 A 扣了但 B 没到账) |
| 隔离性(Isolation) | Isolation | 多个事务并发执行时,彼此隔离,互不干扰(避免并发问题) | 事务 1 读取 A 余额时,事务 2 修改 A 余额 → 事务 1 读取的是隔离后的数据 |
| 持久性(Durability) | Durability | 事务提交后,结果永久保存到数据库(即使数据库崩溃,数据也不丢失) | 转账成功后,即使数据库重启,A 扣 100、B 加 100 的结果仍存在 |
2. 并发事务的三大问题
当多个事务同时操作同一批数据时,若隔离性不足,会引发三类典型问题:
| 并发问题 | 具体表现 | 示例(事务 T1 读取数据,事务 T2 修改数据) |
|---|---|---|
| 脏读(Dirty Read) | T1 读取 T2 未提交的修改 → T2 回滚后,T1 读取的是 “无效数据” | T2 给 A 加 100(未提交)→ T1 读 A 余额为 1100 → T2 回滚 → T1 基于 1100 做业务,结果错误 |
| 不可重复读(Non-Repeatable Read) | T1 多次读取同一数据 → T2 提交修改后,T1 两次读取结果不一致 | T1 第一次读 A 余额 1000 → T2 给 A 加 100(提交)→ T1 第二次读 A 余额 1100,结果不同 |
| 幻读(Phantom Read) | T1 按条件查询数据 → T2 插入 / 删除符合条件的行 → T1 再次查询,行数变化 | T1 查 “余额> 500 的用户”(2 人)→ T2 新增 1 个余额 600 的用户(提交)→ T1 再次查询,结果为 3 人 |
3. 事务隔离级别:解决并发问题
数据库通过 隔离级别 控制并发事务的干扰程度,Spring 支持数据库的所有隔离级别,并新增 DEFAULT(继承数据库默认级别)。不同级别对并发问题的解决能力不同,性能也不同:
| 隔离级别 | 解决脏读 | 解决不可重复读 | 解决幻读 | 性能 | 数据库默认(常见) |
|---|---|---|---|---|---|
| READ_UNCOMMITTED | ❌ | ❌ | ❌ | 最高 | 无 |
| READ_COMMITTED | ✅ | ❌ | ❌ | 较高 | Oracle、SQL Server |
| REPEATABLE_READ | ✅ | ✅ | ❌ | 中等 | MySQL(InnoDB) |
| SERIALIZABLE | ✅ | ✅ | ✅ | 最低 | 无 |
| DEFAULT(Spring 新增) | 继承数据库默认级别 | 继承数据库默认级别 | 继承数据库默认级别 | 取决于数据库 | - |
Spring AOP
Spring AOP 深度解析:从原理到实战
Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的核心特性之一,旨在解决横切关注点(如日志、事务、权限)在代码中分散、冗余的问题。它通过动态代理技术,将横切逻辑与业务逻辑解耦,实现 “一次定义,多处复用”。从 “核心价值→概念体系→动态代理→实战配置→避坑指南” 五个维度,彻底拆解 Spring AOP 的底层机制与使用方法。
为什么需要 Spring AOP?—— 解决横切关注点的痛点
在传统开发中,日志、事务、异常处理等横切关注点(跨越多个模块的通用逻辑)会嵌入到业务代码中,导致三大核心问题:
| 问题 | 具体表现 | 示例场景 |
|---|---|---|
| 代码冗余 | 相同的日志 / 事务逻辑重复出现在数十个方法中,修改时需逐一修改 | 每个 Service 方法都要写 log.info("方法开始执行") |
| 代码混乱 | 业务逻辑与横切逻辑混杂,难以区分核心功能与辅助功能 | 一个 createOrder() 方法中,订单业务、日志、事务代码交织 |
| 维护困难 | 横切逻辑变更时,需修改所有相关业务类,风险高、效率低 | 日志格式从 “INFO” 改为 “DEBUG”,需修改所有日志语句 |
AOP 的解决方案:将横切逻辑横向抽取为 “切面(Aspect)”,通过动态代理技术,在不修改业务代码的前提下,将切面 “织入” 到目标方法的指定位置(如方法执行前、执行后),实现与业务逻辑的解耦。
Spring AOP 核心概念:理解 AOP 的 “语言体系”
AOP 有一套标准化的概念体系,是理解和使用 AOP 的基础。用 “日志切面” 案例对应解释每个概念:
| 概念 | 官方定义 | 日志切面案例对应 |
|---|---|---|
| 横切关注点 | 从业务逻辑中抽取的、跨越多个模块的通用逻辑(如日志、事务) | 所有方法的 “执行日志记录” 逻辑 |
| 目标对象(Target) | 被切面织入的对象(即业务逻辑对象) | OrderService、UserService 等业务类实例 |
| 代理对象(Proxy) | 目标对象被织入切面后,Spring 生成的代理对象(包含目标方法 + 增强逻辑) | OrderService 的代理对象,调用 createOrder() 时会先记录日志 |
| 连接点(Joinpoint) | 程序执行过程中可插入切面的 “点”(Spring AOP 中仅支持方法执行) | OrderService.createOrder()、UserService.getUser() 等方法 |
| 切点(Pointcut) | 对连接点的 “筛选规则”,定义哪些方法会被织入切面(即 “要增强哪些方法”) | “所有 Service 类的 public 方法” |
| 通知(Advice) | 切面的具体增强逻辑(即 “要做什么”),按执行时机分为 5 种类型 | “方法执行前记录日志”“方法异常时记录错误日志” |
| 织入(Weaving) | 将通知(Advice)应用到目标对象(Target)的过程(Spring 中是运行期织入) | 动态代理生成时,将日志逻辑嵌入 createOrder() 方法的执行流程 |
| 切面(Aspect) | 切点(Pointcut)+ 通知(Advice)的组合(即 “对哪些方法,做什么增强”) | “对所有 Service 的 public 方法,执行前记录日志” |
| 通知器(Advisor) | 简化版切面,仅包含 “一个切点 + 一个通知”(Spring 早期接口式 AOP 常用) | “对 createOrder() 方法,执行后记录事务状态” |
Spring AOP 的动态代理:AOP 的 “实现引擎”
Spring AOP 不修改目标类的字节码,而是在运行期通过动态代理生成代理对象,将切面逻辑织入。核心支持两种代理方式,由 DefaultAopProxyFactory 决定选择逻辑。
1. 代理方式的选择逻辑(源码解析)
Spring 通过 DefaultAopProxyFactory.createAopProxy() 方法选择代理方式: