Mysql 范式 事务 锁
三大范式
非标准化形式: 主键不能重复;不出现重复记录
字段原子性,不能再分
反例: 联系方式 =》(电话,邮箱)
- 不能存在部分依赖。 随着主键值的变化,其它列名也必须随之而变化,如果主键是几个列名的组合,其它列名(副键)必须同时被这几个列名影响,少一个的话,不行。
反例: 组件id,价格,供应商id,供应商名称,供应商地址。 同一个组件有可能由不同的供应商提供,故 组件 id 和 供应商 id 组成主键, 价格 和 主键 完全依赖; 供应商名称和地址 只依赖于 供应商 id, 部分依赖
- 不能存在传递依赖。 副键与副键之间,不能存在依赖关系。
反例: 学号,姓名, 性别,班级,班主任。班主任 受到 班级 的影响,就需要另外 建一张表。
事务
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。事务的使用是数据库管理系统区别文件系统的重要特征之一。
4个特性
- 原子性
要么做完,要么不做,没有中间停滞环节。
- 一致性
从一种状态变成另一种状态。开始和结束后,完整性约束没有变化。
- 隔离性
多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务的运行效果。即,每个事务有各自完整的数据空间。
mysql 通过锁机制来保证事务的隔离性。
- 持久性
事务一旦提交,其结果就是永久性的。
事务的隔离等级
- READ UNCOMMITTED(读未提交)脏读
事务2 读到了 事务1 未提交的数据。
- READ COMMITTED (读提交) 不可重复读
事务2 只能读到 事务1 已经提交的数据。是 Oracle 和 SQL Server 的默认隔离级别。
- REPEATABLE READ (可重复读) 幻读
事务2 不会读到 事务1 对已有数据的修改,即使事务1的修改 已提交,也就是说,事务2 开始时读到的数据是什么,在事务2 提交前的任意时刻,这些数据的值都是一样的。 mysql 的默认隔离级别。
如果 根据读取数据插入或修改时,与数据库真实数据发生冲突(完整性和一致性),mysql 称为幻读。(如,主键冲突等)。
- SERIALIZABLE(序列化)
事务是串行顺序执行的,MySql 的 InnoDB 会给读操作隐式的加一把读共享锁,从而避免了脏读、不可重复读、幻读的问题。
锁
锁也是数据库管理系统区别文件系统的重要特征之一。锁机制使得在对数据库进行并发访问时,可以保障数据的完整性和一致性。
Mysql 的锁其实可以按很多种形式分类:
- 按加锁机制分,可分为乐观锁与悲观锁.
- 按兼容性来分,可分为X锁与S锁.
- 按锁粒度分,可分为表锁,行锁,页锁.
- 按锁模式分,可分为记录锁, gap锁, next-key锁, 意向锁, 插入意向锁.
InnoDB 实现了两种类型的行级锁:
- 共享锁 (S 锁): 允许事务读取一行数据。 select * from TableName where … lock in share mode;
- 独占锁 (X 锁): 允许事务删除或更新一行数据。 select * from TableName where … for update;
S 锁与 S锁 是兼容的,X 锁和其它锁都不兼容。
为了实现多粒度的锁机制,InnoDB 还有两种内部使用的 意向锁 ,由 InnoDB 自动添加,且都是表级别的锁。
- 意向共享锁 (IS):事务即将给表中的各个行设置共享锁,事务给数据行加 S 锁前必须获得该表的 IS 锁。
- 意向排他锁 (IX):事务即将给表中的各个行设置排他锁,事务给数据行加 X 锁前必须获得该表 IX 锁。
死锁
死锁 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
锁优化建议
- 合理设计索引,让 InnoDB 在索引键上面加锁的时候尽可能准确,尽可能的缩小锁定范围,避免造成不必要的锁定而影响其他 Query 的执行。
- 尽可能减少基于范围的数据检索过滤条件,避免因为间隙锁带来的负面影响而锁定了不该锁定的记录。
- 尽量控制事务的大小,减少锁定的资源量和锁定时间长度。
- 在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少 MySQL 因为实现事务隔离级别所带来的附加成本。