MySQL是一个关系型数据库管理系统。
一、SQL语句分类
- 数据定义语言DDL:create,drop,alter主要为这几个操作,即对逻辑结构等有操作的,其中包括表结构、视图和索引。
- 数据查询语言DQL:select,即查询操作,以select关键字,各种简单查询、连接查询都属于DQL。
- 数据操纵语言DML:insert,update,delete主要为这几个操作,即对数据进行操作的,
- 数据控制功能DCL:grant,revoke,commit,rollback主要为这几个操作,即对数据库安全性、完整性等有操作的,可以理解为权限控制。
二、MySQL事务
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
四个特性,ACID:
- A(原子性Atomicity):原子性指的是事务是一个不可分割的,要么都执行要么都不执行
- C(一致性Consistency):事务必须使得数据库从一个一致性状态,到另一个一致性状态
- I(隔离性Isolation):指的是一个事务的执行,不能被其他的事务所干扰
- D(持久性Durability):持久性指的是一个事务一旦提交了之后,对数据库的改变就是永久的
并发事务处理带来的问题
更新丢失(Lost Update):事务A和事务B选择同一行,然后基于最初选定的值更新该行时,由于两个事务都不知道彼此的存在,就会发生丢失更新问题。
脏读(Dirty Reads):事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
不可重复读(Non-Repeatable Reads):事务 A 多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
幻读(Phantom Reads):幻读与不可重复读类似。它发生在一个事务A读取了几行数据,接着另一个并发事务B插入了一些数据时。在随后的查询中,事务A就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
幻读和不可重复读的区别:
- 不可重复读的重点是修改:在同一事务中,同样的条件,第一次读的数据和第二次读的数据不一样。(因为中间有其他事务提交了修改)
- 幻读的重点在于新增或者删除:在同一事务中,同样的条件,,第一次和第二次读出来的记录数不一样。(因为中间有其他事务提交了插入/删除)
创建一个事务
事务可以划分为两大类,显示事务和隐式事务。隐式的事务很简单,比如insert、delete、update和select;显示事务就是很明显的开始和结束标记。接着来创建一个显示事务。
- 禁用步骤提交功能 set autocommit = 0
- 开启一个事务 start transaction
- SQL语句:update table user set money=500 where name = "张三";update table user set money=1500 where name = "李四";
- 结束事务,commit或者rollback。
并发事务处理带来的问题解决办法
“更新丢失”通常是应该完全避免的。但防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决,因此,防止更新丢失应该是应用的责任。
“脏读” 、 “不可重复读”和“幻读” ,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决:一种是加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。
另一种是数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个版本。
事务的隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 | |
读未提交(read-uncommitted) | 是 | 是 | 是 | 三种现象都可能发生 |
不可重复读(read-committed) | 否 | 是 | 是 | 只允许读取已提交的数据 |
可重复读(repeatable-read) | 否 | 否 | 是 | 读取期间,其他事务不能更新 |
-
未提交读(Read Uncommitted):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- 提交读(Read Committed):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- 可重复读(Repeated Read):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
查看当前数据库的事务隔离级别:show variables like 'tx_isolation'
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
数据库的事务隔离越严格,并发副作用越小,但付出的代价就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
Read uncommitted:读未提交,就是一个事务可以读取另一个未提交事务的数据。
Read committed:读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个地方没有万能的原则。MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。
这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串行化)隔离级别,而且保留了比较好的并发性能。
三、MySQL三大范式
第一范式
1NF,强调的是列的原子性,也就是列不能再被分割。如电话列可进行拆分---家庭电话、公司电话
第二范式
2NF,首先是 1NF,另外包含两部分内容,一是表必须有主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。例如:订单表(订单编号、产品编号、定购日期、价格、……),"订单编号"为主键,"产品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。
第三范式
3NF,首先是 2NF,目标是确保每列都和主键列直接相关,而不是间接相关(另外非主键列必须直接依赖于主键,不能存在传递依赖).
为了理解第三范式,需要根据Armstrong公里之一定义传递依赖。假设A、B和C是关系R的三个属性,如果A-〉B且B-〉C,则从这些函数依赖中,可以得出A-〉C,如上所述,
依赖A-〉C是传递依赖。
例如:订单表(订单编号,定购日期,顾客编号,顾客姓名,……),初看该表没有问题,满足第二范式,每列都和主键列"订单编号"相关,再细看你会发现"顾客姓名"和"顾客
编号"相关,"顾客编号"和"订单编号"又相关,最后经过传递依赖,"顾客姓名"也和"订单编号"相关。为了满足第三范式,应去掉"顾客姓名"列,放入客户表中。