1. 为什么要使用数据库 ?
1. 数据可以永久保存 !
2. 使用SQL语句,查询方便效率高 !
3. 管理数据方便 !
2. 什么是 SQL ?
结构化查询语言 (Structured Query Language) 简称 SQL ,是一种数据库查询语言 。
3. SQL 的作用
用于存取数据、查询、更新和管理数据库系统 。
4. 什么是 MySQL ?
MySQL 是一个关系型数据库管理系统,属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL 是最好的关系型数据库管理系统应用软件之一。在 Java 企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展 。
5. 数据库三大范式是什么 ?
第一范式:每个列都不可以再拆分
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分
第三范式:在第二范式的基础上,非主键列完全依赖于主键,而不依赖于其他非主键 。
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计 。
6. MySQL 有关权限的表都有哪几个 ?
MySQL 服务器通过权限表来控制用户对数据库的访问,权限表存放在 MySQL 数据库里,由 mysql_install_db 脚本初始化。这些权限表分别 user,db,table_priv,columns_priv 和 host 。
下面分别介绍一下这些表的结构和内容:
user 权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的 。
db 权限表:记录各个帐号在各个数据库上的操作权限 。
table_priv 权限表:记录数据表级的操作权限 。
columns_priv 权限表:记录数据列级的操作权限 。
host 权限表:配合db权限表对给定主机上数据库级操作权限作更细致的控制 ,这个权限表不受GRANT和 REVOKE语句的影响 。
7. MySQL的binlog有有几种录入格式?分别有什么区别?
有三种格式,statement,row和mixed。
1. statement模式下,每一条会修改数据的sql都会记录在binlog中。不需要记录每一行的变化,减少 了binlog日志量,节约了IO,提高性能。由于sql的执行是有上下文的,因此在保存的时候需要保存 相关的信息,同时还有一些使用了函数之类的语句无法被记录复制。
2. row级别下,不记录sql语句上下文相关信息,仅保存哪条记录被修改。记录单元为每一行的改动, 基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如altertable),因此这种模式的 文件保存的信息太多,日志量太大。
3. mixed,一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。 此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行 记录。
8. MySQL 有哪些数据类型 ?
MySQL数据类型
分类 类型名称 说明
整数类型 tinyint 很小的整数(8位二进制)
smallint 小的整数(16位二进制)
int(integer) 普通大小的整数(32位二进制)
小数类型 float 单精度浮点数
double 双精度浮点数
decimal(m,d) 压缩严格的定点数
日期类型 year
YYYY
1998
time
HH:MM:SS
20:58:14
date
YYYY -MM -DD
1998 -09 -14
datetime
YYYY -MM -DD HH:MM:SS
1998 -09 -14 20:58:20
timestamp
YYYY-MM-DD HH:MM:SS
1998 -09 -14 20:57:54
文本、二进制 类型 CHAR(S) S 为 0~65535 之 间的整数
VARCHAR(S) S 为 0~65535 之 间的整数
TINYBLOB 允许长度0~255字节
BLOB 允许长度0~65535字节
MEDIUMBLOB 允许长度0~167772150字节
LONGBLOB 允许长度0~4294967295字节
TINYTEXT 允许长度0~255字节
TEXT 允许长度0~65535字节
MEDIUMTEXT 允许长度0~167772150字节
LONGTEXT 允许长度0~4294967295字节
VARBINARY(M) 允许长度0~M个字节的变长字节字符串
BINARY(M) 允许长度0~M个字节的定长字节字符
整数类型,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示1字节、2字节、3字 节、4字节、8字节整数。任何整数类型都可以加上UNSIGNED属性,表示数据是无符号的,即非负整 数。
长度:整数类型可以被指定长度,例如:INT(11)表示长度为11的INT类型。长度在大多数场景是没有意 义的,它不会限制值的合法范围,只会影响显示字符的个数,而且需要和UNSIGNEDZEROFILL属性配合 使用才有意义。
例子,假定类型设定为INT(5),属性为UNSIGNEDZEROFILL,如果用户插入的数据为12的话,那么数据库实际存储数据为00012。
实数类型,包括FLOAT、DOUBLE、DECIMAL。DECIMAL可以用于存储比BIGINT还大的整型,能存储 精确的小数。而FLOAT和DOUBLE是有取值范围的,并支持使用标准的浮点进行近似计算。 计算时FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串进行处理。
字符串类型,包括VARCHAR、CHAR、TEXT、BLOBVARCHAR用于存储可变长字符串,它比定长类型更 节省空间。
VARCHAR使用额外1或2个字节存储字符串长度。列长度小于255字节时,使用1字节表示,否则使用2字 节表示。
VARCHAR存储的内容超出设置的长度时,内容会被截断。
CHAR是定长的,根据定义的字符串长度分配足够的空间。
CHAR会根据需要使用空格进行填充方便比较。
CHAR适合存储很短的字符串,或者所有值都接近同一个长度。
CHAR存储的内容超出设置的长度时,内容同样会被截断。
使用策略: 对于经常变更的数据来说,CHAR比VARCHAR更好,因为CHAR不容易产生碎片。 对于非常短的列,CHAR比VARCHAR在存储空间上更有效率。 使用时要注意只分配需要的空间,更长的列排序时会消耗更多内存。尽量避免使用TEXT/BLOB类型,查 询时会使用临时表,导致严重的性能开销。
枚举类型(ENUM),把不重复的数据存储为一个预定义的集合。有时可以使用ENUM代替常用的字符 串类型。ENUM存储非常紧凑,会把列表值压缩到一个或两个字节。ENUM在内部存储时,其实存的是 整数。尽量避免使用数字作为ENUM枚举的常量,因为容易混乱。排序是按照内部存储的整数 日期和时间类型,尽量使用timestamp,空间效率高于datetime,用整数保存时间戳通常不方便处理。 如果需要存储微妙,可以使用bigint存储。 看到这里,这道真题是不是就比较容易回答了。
日期和时间类型,尽量使用timestamp,空间效率高于datetime,用整数保存时间戳通常不方便处理。 如果需要存储微妙,可以使用bigint存储。
9. 引擎
1. MySQL存储引擎与 MyISAM 和 InnoDB区别 ?
存储引擎Storageengine:MySQL中的数据、索引以及其他对象是如何存储的,是一套文件系统的实现。
常用的存储引擎有以下:
1. Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
2. MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。
3. MEMORY引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。
存储引擎 MyISAM 和 InnoDB 的区别
MyISAM InnoDB
存储结构 张表被存放在三个文件:frm-表格定义、MYD(MYData)-数据 文件、MYI(MYIndex)-索引文件 所有的表都保存在同一个数据文件中 (也可能是多个文件,或者是独立的表 空间文件),InnoDB表的大小只受限 于操作系统文件的大小,一般为2GB
存储空间 MyISAM可被压缩,存储空间较 小 InnoDB的表需要更多的内存和存储, 它会在主内存中建立其专用的缓冲池用 于高速缓冲数据和索引
可移植性、备份 及恢复 由于MyISAM的数据是以文件的 形式存储,所以在跨平台的数据 转移中会很方便。在备份和恢复 时可单独针对某个表进行操作 免费的方案可以是拷贝数据文件、备份 binlog,或者用mysqldump,在数据 量达到几十G的时候就相对痛苦了
文件格式 数据和索引是分别存储的,数 据.MYD,索引.MYI 数据和索引是集中存储的,.ibd
记录存储顺序 按记录插入顺序保存 按主键大小有序插入
外键 不支持 支持
事务 不支持 支持
锁支持(锁是避 免资源争用的一 个机制,MySQL 锁对用户几乎是 透明的) 表级锁定 行级锁定、表级锁定,锁定力度小并发 能力高
SELECT MyISAM 更优
INSERT、 UPDATE、 DELETE InnoDB 更优
select count(*) myisam更快,因为 MyISAM 内部维护了一个计数器,可以直接调取。
索引的实现方式 B+树索引,myisam是堆表 B+树索引,Innodb是索引组织表
哈希索引 不支持
支持
全文索引 支持 不支持
1. InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
2. InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。
3. MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
4. InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会 非常高效。
2. InnoDB引擎的4大特性
插入缓冲(insertbuffer)
二次写 (doublewrite)
自适应哈希索引 (ahi)
预读 (readahead)
3. 存储引擎选择
如果没有特别的需求,使用默认的Innodb即可。
MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。
Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高, 支持事务和外键。比如OA自动化办公系统。
10. 索引
1. 什么是索引 ?
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新 数据库表中数据。索引的实现通常使用B树及其变种 B+树。 更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。
2. 索引使用的场景 ( 重点 )
上图中,根据 id 查询记录,因为id字段仅建立了主键索引,所以此 SQL 执行可选的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的依据 。
1__ 增加一个没有建立索引的字段
2__ alter table student add sex char(1) ;
3__ 按 sex 检索时可选的索引为null
4__ explain select * from student where sex= '男' ;
!!!注意提示:
可以尝试在一个字段未建立索引时,根据该字段查询的效率,然后对该字段建立索引 (alter table 表名 add index(字段名) ),同样的SQL执行的效率,你会发现查询效率会有明显的提升(数据量越大越明显)。
order by
当我们使用 order by 将查询结果按照某个字段排序时,如果该字段没有建立索引,那么执行计划会将查询出所有数据使用外部排序(将数据从硬盘分批读取到内存使用内部排序, 最后合并排序结果),这个操作是很影响性能的,因为需要将查询涉及到的所有数据从磁盘中读到内存 (如果单条数据过大或者数据量过多都会降低效率),更别提读到内存之后的排序了。 但是如果我们对该字段建立索引 [^^^ 注意提示] ,那么由于索引本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如果是分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用像上述那取出所有数据进行排序再返回某个范围内的数据。(从磁盘取数据是最影响性能的)
join
对 join 语句匹配关系(on)涉及的字段建立索引能够提高效率
索引覆盖
如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原始数据(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。 因此我们需要尽可能的在 select 后只写必要的查询字段,以增加索引覆盖的几率。 这里值得注意的是不要想着为每个字段建立索引,因为优先使用索引的优势就在于其体积小 。
3. 索引有哪几种类型 ?
主键索引 : 数据列不允许重复,不允许为NULL, 一个表只能有一个主键 。
唯一索引 : 数据列不允许重复,允许为NULL值, 一个表允许多个列创建唯一索引 。
创建唯一索引的方式:
ALTER TABLE [ 表名 ] ADD UNIQUE [ 表列名 ] ;
创建唯一组合索引的方式:
ALTER TABLE [ 表名 ] ADD UNIQUE [ 列1,列2 ] ;
普通索引 : 基本的索引类型,没有唯一性的限制,允许为NULL值 。
创建普通索引的方式:
ALTER TABLE [ 表名 ] ADD INDEX [ 索引名 ] [ 表列名 ] ;
创建普通组合索引的方式:
ALTER TABLE [ 表名 ] ADD INDEX [ 索引名 ] [ 列1,列2,列3 ] ;
全文索引:是目前搜索引擎使用的一种关键技术 。
创建全文索引的方式
ALTER TABLE [ 表名 ] ADD FULLTEXT [ 表列名 ] ;
4. 索引的数据结构(b树,hash)
1. 索引的基本原理
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。 索引的原理很简单,就是把无序的数据变成有序的查询 。
1. 把创建索引列的内容进行排序 。
2. 把排序结果生成倒排表 。
3. 在倒排表内容上拼上数据地址链 。
4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据 。
2. 索引算法有哪些 ?
索引算法有 BTree算法 和 Hash算法
BTree 算法:
BTree 是常用的 mysql 数据库索引算法,也是 mysql 默认的算法。因为它不仅可以被用在=、>、>=、<、<=、between 这些比较操作符上,而且还可以用于 like 操作符,它的查询条件是一个不以通配符开头的 常量,例如:
1. 查询条件不以通配符开头的常量:
SELECT * FROM STUDENT WHERE NAME LIKE '娜%'
2.查询条件以通配符开头,或者没有使用常量,则不会使用索引:
SELECT * FROM STUDENT WHERE NAME LIKE '贺%'
如下图所示!!!
Hash算法 :
Hash索引只能用于对等比较,例如 =、<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引 。
3. 创建索引的原则 [ 重点 ]
1)左前缀匹配原则,组合索引非常重要的原则,mysql 会一直向右匹配直到遇到范围查询(>、<、Like、Between)就停止匹配,比如 a=1 and b=2 and c>3 and d=4 如果建立(a,b,c,d) 顺序的索引,d 是用不到 索引的,如果建立 (a,b,d,c) 的索引则都可以用到,a、b、d 的顺序可以任意调整 。= 和 in 可以乱序,比如a=1 and b=2 and c=3建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
2)较频繁作为查询条件的字段才去创建索引
3)更新频繁字段不适合创建索引
4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,多也就三种,区分度实在太低)
5)尽量的扩展索引,不要新建索引。比如表中已经有 a 的索引,现在要加 (a,b) 的索引,那么只需要修改原来的索引即可
6)定义有外键的数据列一定要建立索引
7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引
8)对于定义为 text、image、bit 的数据类型的列不要建立索引
4. 创建索引的方式
第一种方式:在执行 CREATE TABLE 时创建索引 :
CREATE TABLE USER_INDEX(
id INT PRIMARY KEY, # 主键索引
first_name VARCHAR(16),
last_name VARCHAR(16),
id_card VARCHAR(16),
information TEXT,
KEY NAME (first_name,last_name), # 普通组合索引
FULLTEXT KEY (information), # 全文索引
UNIQUE KEY (id_card)); # 唯一索引
第二种方式:使用 ALTER TABLE 命令去增加索引 :
ALTER TABLE [ table_name ] ADD UNIQUE [ column_list ] ;
ALTER TABLE 用来创建普通索引、UNIQUE——> 唯一索引 、——> PRIMARY KEY 主键索引。 其中 table_name 是要增加索引的表名,column_list 指出对哪些列进行索引,多列时各列之间用逗号分隔。 索引名 index_name 可自己命名,缺省时,MySQL 将根据第一个索引列赋一个名称。另外, ALTER TABLE 允许在单个语句中更改多个表,因此可以在同时创建多个索引 。
第三种方式:使用 CREATE INDEX 命令创建 :
CREATE INDEX [ index_name ] ON table_name [ column_list ] ;
CREATE INDEX 可对表增加 普通索引 或 UNIQUE索引 。( 注意:不能创建PRIMARY KEY 索引 !!!)
5. 删除索引的方式
根据索引名删除 普通索引、唯一索引、全文索引 :ALTER TABLE [ 表名 ] DROP KEY [ 索引名 ]
删除主键索引 ALTER TABLE [ 表名 ] DROP PRIMARY KEY(因为主键只有一个)。
注意:如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引)
上图说明,需要取消自增长再行删除:
alter table user_index
MODIFY id int, #修改列属性
drop PRIMARY KEY
注意:但通常不会删除主键,因为设计主键一定与业务逻辑无关。
6. 创建索引时需要注意什么 ?
1. 非空字段:应该指定为 NOT NULL ,除非想存储 NULL 。在 mysql 中,含有空值很难进行查询优化,因为它们使得索引的统计信息以及比较运算更加复杂 。应该用 0、一个特殊的值或者一个空串代替空值
2. 取值离散大的字段:[ 变量各个取值之间的差异程度 ] 的列放到联合索引的前面,可以通过count() 函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高
3. 索引字段越小越好:数据库的数据存储以页为单位、一页存储的数据越多则一次IO操作获取的数据越大 效率越高
7. 使用查询索引一定能提高查询的性能吗 ?
通常,通过索引查询数据比全表扫描要快、但是我们也必须注意到它的代价。
索引 需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改。这意味着每条记录的INSERT,DELETE,UPDATE 将为此多付出4、5次的磁盘I/O。因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能。
索引范围查询 ( INDEX RANGESCAN ) 适用于两种情况:
1)基于一个范围的检索,一般查询返回结果集小于表中记录数的30%
2)基于非唯一性索引的检索
5. 百万级别或以上的数据如何删除
关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件, 所以当我们对数据的增、改、删,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增、改、删的执行效率。所以、在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的
具体操作:
1. 先删除索引( 此时大概耗时三分多钟 )
2. 然后删除其中无用数据( 此过程需要不到两分钟 )
3. 删除完成后重新创建索引 ( 此时数据量较少 ) 创建索引也非常快,约十分钟左右。
4. 对比之前的直接删除绝对是要快速很多,更别说万一删除中断、一切删除都将会回滚
6. 前缀索引
前缀索引语法:alter table student add index (email(7)),使用字段值的前7个字符建立索引,默认是使用字段的全部内容建立索引。
前提:前缀的标识度高。比如密码就适合建立前缀索引,因为密码几乎各不相同。
实操的难度:在于前缀截取的长度。 我们可以利用 select count(*)/count(distinct left(email,prefixLen)) from student; 通过从调整 prefixLen 的值( 从1自增 )查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前 prefixLen 个字符几乎能确定唯一一条记录 )
7. 联合索引是什么?为什么需要注意联合索引中的顺序 ?
MySQL 可以使用多个字段同时建立一个索引,叫做联合索引。
在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。
具体原因 : MySQL使用索引时需要索引有序,假设现在建立了 " name,age,school "的联合索引,那么索引的排序为: 先按照 name排序,如果 name 相同,则按照 age 排序,如果 age 的值也相等,则按照 school 进行排 序。 当进行查询时,此时索引仅仅按照name 严格有序,因此必须首先使用 name 字段进行等值查询,之后对 于匹配到的列而言,其按照 age 字段严格有序,此时可以使用 age 字段用做索引查找,以此类推。因此在 建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询 需求频繁或者字段选择性高 的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整 。
11. 事务
1. 什么是数据库事务 ?
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库 从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。 假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小 红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
2. 事务的四大特性 ?
关系型数据库需要遵循 ACID 规则,具体内容如下 :
原子性:一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么
全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作 。
一致性:根据定义,一致性是指事务执行前后,数据处于一种合法的状态,这种状态是语义上的而不是语法上的 。[
那什么是合法的数据状态呢 ?
这个状态是满足预定的约束就叫做合法的状态,再通俗一点,这状态是由你自己来定义的。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的!
如果无法保证一致性会怎么样 ?
例一:A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现了此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须大于0。
例二:A账户200元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的余额必须不变。]
隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的 。[ 未提交事务之前, 甲向乙转了两次帐,执行了第一次转账操作后,第二次转账未开始,此时另外一个事务查看甲账户余额操作开始执行,则其看到支票帐户的余额并没有任何变化 ]
持久性:一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响 。
怎么保持数据一致性 ?
1. 从数据库层面,数据库通过原子性、隔离性、持久性来保持一致性。ACID四大特性之中C(一致性)是目的、A(原子性)、C(隔离性)、D(持久性)是手段,是为了保持数据一致性、数据库提供的手段。数据库必须实现AID三大特性,才有可能实现一致性。例如原子性无法保证,显然一致性也无法保证。但是,如果你在事务里故意写出违反约束的代码,一致性还是无法保证的。
例如,你在转账的例子中,你的代码里故意不给乙账户加钱,那一致性还是无法保证。因此,还必须从应用层角度考虑。
2. 从应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据!
3. 什么是 脏读、幻读、不可重复读 ?
脏读:(Drity Read) 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
脏读示例:
张三的工资为 5000 、事务 A 中把他的工资改为 8000、但事务 A 尚未提交 。
与此同时,事务 B 正在读取张三的工资,读取到张三的工资为 8000 。
随后,事务 A 发生异常,而回滚了事务。张三的工资又回滚为 5000 。
最后,事务 B 读取到的张三工资为 8000 的数据即为脏数据,事务 B 做了一次脏读 。
不可重复读:(Non-repeatable read) 在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务使原有的数据更新了 。
不可重复读示例:
在事务 A 中,读取到张三的工资为 5000,操作没有完成,事务还没提交。
与此同时,事务 B 把张三的工资改为 8000,并提交了事务。
随后,在事务 A 中,再次读取张三的工资,此时工资变为 8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
幻读:(Phantom Read) 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数 据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据 是它先前所没有的 。
目前工资为 5000 的员工有 10 人,事务 A 读取所有工资为 5000 的人数为 10 人 。
此时,事务 B 插入一条工资也为 5000 的记录 。
这是,事务 A 再次读取工资为 5000 的员工,记录为 11 人。此时产生了幻读 。