大家好啊,这是一期究极全的Java全套复习流程,这是第五期MySql篇,祖贤女神镇楼嘿嘿嘿。。。
事务4大特性: 原子性、一致性、隔离性、持久性
原⼦性: 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么全不执行
一致性: 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
隔离性: 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;
持久性: ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。
实现保证:
白嫖资料
MySQL的存储引擎InnoDB使用重做日志保证一致性与持久性,回滚日志保证原子性,使用各种锁来保证隔离性。
读未提交: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
读已提交: 允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣。
可重复读: 同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。
可串行化: 最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防⽌脏读、不可重复读以及幻读。
隔离级别 | 并发问题 |
---|---|
读未提交 | 可能会导致脏读、幻读或不可重复读 |
读已提交 | 可能会导致幻读或不可重复读 |
可重复度 | 可能会导致幻读 |
可串行化 | 不会产⽣⼲扰 |
默认隔离级别: 可重复读;
同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改;
可重复读是有可能出现幻读的,如果要保证绝对的安全只能把隔离级别设置成SERIALIZABLE;这样所有事务都只能顺序执行,自然不会因为并发有什么影响了,但是性能会下降许多。
第二种方式,使用更新的版本控制。维护一个字段作为updateversion,修改时updateversion也作为一个参数传入,在条件语句中添加例如where id=? and update_version = ? 当然set里面要update_version+1。这样可以控制到每次只能有一个人更新一个版本。
事务隔离级别RC(read commit)和RR(repeatable read)两种事务隔离级别基于多版本并发控制MVCC(multi-version concurrency control)来实现。
由于RC隔离级别需要保持语句级别的一致性,事务中每一次读取都是访问当前时间点的已提交数据,因此事务中多条查询语句会创建多个不同的ReadView,开销较大,复杂度更高;而对于RR隔离级别,仅需要一个版本的ReadView,消耗更少,因此Mysql默认使用RR隔离级别。
RC隔离级别获得的是语句级读一致性;RR隔离级别获得的是事务级读一致性
对于RC隔离级别,访问的数据是每次语句执行时间点的数据,而对于RR隔离级别,访问的数据是事务中第一条语句执行时间点的数据。
白嫖资料
读未提交:不加锁
读已提交:加行锁,只锁要修改的行
可重复读:加行锁,锁定的是查询的行
可串行化:加表锁,在读取的每张表上加锁
串行化级别:读不同的行,可以并发
Myisam: 支持表锁,适合读密集的场景,不支持外键,不支持事务,索引与数据在不同的文件
Innodb: 支持行、表锁,默认为行锁,适合并发场景,支持外键,支持事务,索引与数据同一文件
InnoDB⽀持⾏级锁(row-level locking)和表级锁,默认为⾏级锁
InnoDB按照不同的分类的锁:
共享/排它锁(Shared and Exclusive Locks):行级别锁,
意向锁(Intention Locks),表级别锁
间隙锁(Gap Locks),锁定一个区间
记录锁(Record Locks),锁定一个行记录
表级锁:
Mysql中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单 ,资源消耗也比较少,加锁快,不会出现死锁 。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
行级锁:
Mysql中锁定 粒度最小 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。 InnoDB支持的行级锁,包括如下几种:
记录锁(Record Lock): 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
间隙锁(Gap Lock): 对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。
Next-key Lock: 锁定索引项本身和索引范围。即Record Lock和Gap Lock的结合。可解决幻读问题。
意向锁:
当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。
MVCC是一种多版本并发控制机制,在大多数情况下代替行级锁,使用MVCC,能降低其系统开销.
MVCC是通过保存数据在某个时间点的快照来实现的. 不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制.
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间。这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID.
InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
1.MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).
2.Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.
原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。客观上,我们认为他就是乐观锁的一整实现方式,就是每行都有版本号,保存时根据版本号决定是否成功。
哈希索引用索引列的值计算该值的hashCode,然后在hashCode相应的位置存执该值所在行数据的物理位置,因为使用散列算法,因此访问速度非常快,但是一个值只能对应一个hashCode,而且是散列的分布方式,因此哈希索引不支持范围查找和排序的功能
因为:
B+树的磁盘读写代价低,更少的查询次数,查询效率更加稳定,有利于对数据库的扫描
相对B树,B+树是B树的升级版,只是把非叶子节点冗余一下,这么做的好处是为了提高范围查找的效率,解决数据库遍历效率低下问题;B+树只有叶节点存放数据,其余节点用来索引,而B树是每个索引节点都会有Data域。
在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树与B+树可以有多个子女,从几十到上千,可以降低树的高度。
磁盘预读原理:将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
聚簇索引: 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据
非聚簇索引: 将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置
聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。
白嫖资料
普通索引 需要扫描两遍索引树
(1)先通过普通索引定位到主键值id=5;
(2)在通过聚集索引定位到行记录;
这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。
覆盖索引:如果where条件的列和返回的数据在一个索引中,那么不需要回查表,那么就叫覆盖索引。
实现覆盖索引:常见的方法是,将被查询的字段,建立到联合索引里去。
CREATE TABLE 表名( 字段名 数据类型 [完整性约束条件],
……, [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [索引名](字段名1 [(长度)] [ASC | DESC]) [USING 索引方法] );说明: UNIQUE:可选。表示索引为唯一性索引。 FULLTEXT:可选。表示索引为全文索引。 SPATIAL:可选。表示索引为空间索引。
INDEX和KEY:用于指定字段为索引,两者选择其中之一就可以了,作用是一样的。 索引名:可选。给创建的索引取一个新名称。
字段名1:指定索引对应的字段的名称,该字段必须是前面定义好的字段。 长度:可选。指索引的长度,必须是字符串类型才可以使用。
ASC:可选。表示升序排列。 DESC:可选。表示降序排列。 注:索引方法默认使用B+TREE。ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [索引名]
(字段名1 [(长度)] [ASC | DESC]) [USING 索引方法];或
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX 索引名 ON 表名(字段名) [USING
索引方法];
1.对查询进行优化,应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断
3.应尽量避免在 where 子句中使用!=或<>操作符
4.in 和 not in 要慎用
否则将导致引擎放弃使用索引而进行全表扫描
mysql> explain select * from staff;
±—±------------±------±-----±--------------±-----±--------±-----±-----±------+ | id | select_type | table | type | possible_keys | key | key_len |
ref | rows | Extra |
±—±------------±------±-----±--------------±-----±--------±-----±-----±------+ | 1 | SIMPLE | staff | ALL | NULL | NULL | NULL |
NULL | 2 | NULL |
±—±------------±------±-----±--------------±-----±--------±-----±-----±------+ 1 row in set
列 | 含义 |
---|---|
id | 查询序号,序号越大越先执行,一样则按顺序执行 |
select_type | 查询类型,SIMPLE、PRIMARY、UNION、SUBQUERY等 |
table | 表名 |
type | join类型,const,eq_ref,ref等 |
possible_keys | join类型 |
key | 实际选择的索引 |
ken_len | 索引的长度 |
ref | 与索引作比较的列 |
rows | 要检索的行数 |
Extra | 额外信息 |
16、最左前缀!!联合索引B+树是如何建立的?是如何查询的?当where子句中出现>时,联合索引命中是如何的?
最左前缀原则主要使用在联合索引中,联合索引的B+Tree是按照第一个关键字进行索引排列的。
联合索引的底层是一颗B+树,那么联合索引的底层也就是一颗B+树,只不过联合索引的B+树节点中存储的是键值。由于构建一棵B+树只能根据一个值来确定索引关系,所以数据库依赖联合索引最左的字段来构建。
采用>、<等进行匹配都会导致后面的列无法走索引,因为通过以上方式匹配到的数据是不可知的。
白嫖资料
查询语句:
select * from student A where A.age='18' and A.name='张三';
结合上面的说明,我们分析下这个语句的执行流程:
更新语句:
update student A set A.age='19' where A.name='张三';
我们来给张三修改下年龄,在实际数据库肯定不会设置年龄这个字段的,不然要被技术负责人打的。其实这条语句也基本上会沿着上一个查询的流程走,只不过执行更新的时候肯定要记录日志啦,这就会引入日志模块了,mysql 自带的日志模块式binlog(归档日志),所有的存储引擎都可以使用,我们常用的InnoDB引擎还自带了一个日志模块redo log,我们就以InnoDB模式下来探讨这个语句的执行流程。流程如下:
第一范式(1NF)列不可分割
第二范式(2NF)属性完全依赖于主键 [ 消除部分子函数依赖 ]
第三范式(3NF)属性不依赖于其它非主属性 [ 消除传递依赖 ]
left join(左联接) 返回包括左表中的所有记录和右表中关联字段相等的记录
right join(右联接) 返回包括右表中的所有记录和左表中关联字段相等的记录
inner join(等值连接) 只返回两个表中关联字段相等的行
白嫖资料
MySQl主从复制:
原理:将主服务器的binlog日志复制到从服务器上执行一遍,达到主从数据的一致状态。
过程:从库开启一个I/O线程,向主库请求Binlog日志。主节点开启一个binlog dump线程,检查自己的二进制日志,并发送给从节点;从库将接收到的数据保存到中继日志(Relay log)中,另外开启一个SQL线程,把Relay中的操作在自身机器上执行一遍
优点:
作为备用数据库,并且不影响业务
可做读写分离,一般是一个写库,一个或多个读库,分布在不同的服务器上,充分发挥服务器和数据库的性能,但要保证数据的一致性
**binlog记录格式:**statement、row、mixed
基于语句statement的复制、基于行row的复制、基于语句和行(mix)的复制。其中基于row的复制方式更能保证主从库数据的一致性,但日志量较大,在设置时考虑磁盘的空间问题
异步复制:
在异步复制中,主库执行完操作后,写入binlog日志后,就返回客户端,这一动作就结束了,并不会验证从库有没有收到,完不完整,所以这样可能会造成数据的不一致。
半同步复制:
当主库每提交一个事务后,不会立即返回,而是等待其中一个从库接收到Binlog并成功写入Relay-log中才返回客户端,所以这样就保证了一个事务至少有两份日志,一份保存在主库的Binlog,另一份保存在其中一个从库的Relay-log中,从而保证了数据的安全性和一致性。
全同步复制:
白嫖资料
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
“主从复制有延时”,这个延时期间读取从库,可能读到不一致的数据。
半同步复制法:
当主库每提交一个事务后,不会立即返回,而是等待其中一个从库接收到Binlog并成功写入Relay-log中才返回客户端,所以这样就保证了一个事务至少有两份日志,一份保存在主库的Binlog,另一份保存在其中一个从库的Relay-log中,从而保证了数据的安全性和一致性。
全同步复制法:
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
缓存记录写key法:
在cache里记录哪些记录发生过的写请求,来路由读主库还是读从库
白嫖资料