ACID
原子性(Atomicity):操作过程不可分割,要么都成功,要么都失败
一致性(Consistency):事物操作之后,操作前后数据不变;比如转账减少的跟增加的值不变
隔离性(Isolation):多个事物之间的操作是分隔的,互不干扰,并发控制机制
如果有多个事务去操作同一个数据的时候,就会事务并发问题(双11在线抢购 秒杀)
持久性(Durability):成功的完成一个事物处理后,最终commit把数据将永久保存在数据库;
Mysql事务
mysql> select * from students;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
1 row in set (0.00 sec)
1.Read Uncommitted–Dirty Read ,隔离级别最低的一种事务级别,
未提交的更改导致另外一个事务提交前后查询的数据不一致,更改数据后回滚数据,前后读取数据发现不一致
事务A | 事务B | |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE students SET name = ‘Bob’ WHERE id = 1; | |
4 | SELECT * FROM students WHERE id = 1; | |
5 | ROLLBACK; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
2.Read Committed(ORACLE默认级别) –不可重复读
事务提交后,另一个事务在这个事务开始前与事务提交完查询后的数据不一致
时刻 | 事务A | 事务B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 1; | |
4 | UPDATE students SET name = ‘Bob’ WHERE id = 1; | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
3.Repeatable Read(mysql Innodb默认级别)–幻读
也即在一次事务范围内多次进行查询,如果其他并发事务中途插入了新的记录,那么之后的查询会读取到这些“幻影”行。
事务内对同一数据的多次读取都是一致的
事务A | 事务B | |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 99; | |
4 | INSERT INTO students (id, name) VALUES (99, ‘Bob’); | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 99; | |
7 | UPDATE students SET name = ‘Alice’ WHERE id = 99; | |
8 | SELECT * FROM students WHERE id = 99; | |
9 | COMMIT; |
4.Serializable
**Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。**效率会大大下降,应用程序的性能会急剧降低
总结:
脏读是因为在读是时候没有加共享锁(又称为读锁,可以查看但无法修改和删除的一种数据锁。)
不可重复读是因为没有遵循两阶段加锁(在一个事务里面,分为加锁(lock)阶段和解锁(unlock)阶段,也即所有的lock操作都在unlock操作之前),即在释放锁之后不能申请锁,所有锁的申请必须在释放之前。
幻读可能是因为锁的颗粒度问题。如果是严格按照两阶段锁的模型,即使读取不存在的元素,也要将该元素上锁,如果是这样的话,那insert语句会失败,也就不会有幻读的问题。但是mysql里面当使用索引时是使用行锁,在可重复读这个隔离级别不会为不存在键上锁,所以会存在幻读的问题。这个主要是为性能考虑,比如select x where x<= 90 这条语句,可能表里面只有x=3, x=50, x=100三条记录,如果要避免幻读只能把x=1到x=90都上锁,那样代价就太高了。
当然mysql也可能使用多版本时间戳的乐观锁,那机制可能就与上面不同了
增、删数据时会出现幻读。
不可重复读的重点是修改数据Update,幻读的重点是增删数据Insert delete。
聚簇索引和非聚簇索引
数据库中的B+树索引分聚簇索引和非聚簇索引
区别在于叶节点是否存的是一整行信息,聚集索引就像按照字典拼音顺序查找,非聚集缩影就像按照偏旁部首去查找
非聚簇索引表的表数据和索引是分开存储的
聚簇索引表的表数据和索引是一起存储的,缺点:插入速度严重依赖于插入顺序并且更新主键的代价很高,因为将会导致被更新的行移动
3NF
第一范式(1NF)
每一列都是不可分割的原子数据项,强调的是列的原子性
第二范式
要求实体的属性完全依赖于主关键字(每个表必须有且仅有一个数据元素为主键(Primary key),其他属性需完全依赖于主键)
第三范式
数据表中的每一列都和主键直接相关,而不能间接相关(在第二范式基础上消除传递依赖)
什么是事务
是数据库操作的最小工作单元,
是作为单个逻辑工作单元执行的一系列操作;
这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;
事务是一组不可再分割的操作集合
泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
参数化类型
泛型类型信息将在编译处理是被擦除,这个过程即类型擦除
Java编译器生成字节码是不包涵泛型信息的
MySQL索引
什么是索引?
索引是一种数据结构,用来高效查询的数据库中的数据。
**Mysql中索引主要两种:**Hash索引和B+Tree索引,InnoDB默认索引是B+树索引
- Hash索引: 底层是哈希表KV存储,数据存储是没有任何规律,导致了hash索引更适合等值查询,不适合范围查询。并且hash索引的索引是hashcode,索引无法排序,也不支持联合索引(两个或以上的字段共同构成一个索引)的最左匹配原则;由于哈希碰撞,大量重复键效率很低。InnoDB的哈希索引是自适应的,InnoDB自动为表生成哈希索引、不能人为干预,InnoDB的自适应哈希索引会基于缓冲池中的B+树构造,将某些高频使用的数据页建立哈希索引。
最左匹配原则的成因:第一个字段是绝对有序的,从第二个字段开始是无序的,这就解释了为什么直接使用第二字段进行条件判断用不到索引了(从第二个字段开始,无序,无法走 B+ Tree 索引),如果我们想使用联合索引中尽可能多的列,搜索条件中的各个列必须是联合索引中从最左边连续的列
- B+树索引:底层是B+树,而B+树是多路查找树,节点有序(左子节点小于父节点、父节点小于右子节点),范围查找不需要全表扫描。
B+树由来?
二叉查找树=》二叉平衡树=》B树=》B+树。
二叉查找树左节点总是小于根,右节点总是大于根。但二叉查查找树容易退化成链表。为此引入了平衡的概念,并提出了二叉平衡树(AVL)。二叉平衡树中规定任意节点的左右子树高度最大差为1,为此需要通过旋转(左旋、右旋)来保证树的平衡性。
由于内存易失性,索引一边存储在磁盘中,由于磁盘较慢的IO速度,所以我们应尽量减少从磁盘读取数据的次数。二叉平衡树由于高度较高并且每个节点仅存一个数据,不适应这种场景。我们需要 一种高度较低、一个节点能存多条数据的数据结构。这就是B树。
B树允许一个节点能存多条数据,并且左节点总是小于根,右节点总是大于根。为了减少高度,允许一个节点可以多叉,但B树无法进行范围查找。并且由于B树的非叶节点也存了数据占用空间,导致了相应的存的键也会少一点。
针对B树缺点提出了B+树。B+树仅叶子节点保存数据页,非叶子节点仅存键值;B+树的叶子节点通过双向链表连接,这样范围查找仅需要遍历一次(空间局限性导致。B+树不仅层数更少,存放数据也更多,IO次数也少了。B+树是平衡的多路搜索树
为什么不用XX树而用B+树?
不用二叉查找树?高度太高了
不用二叉平衡树?苛刻的平衡条件需要反复旋转
不用B树?B树在相同空间存的键少,并且不适合范围查找,查找也不稳定(有时在根节点有时候又查到叶子节点)
不用红黑树?虽然红黑树的平衡条件不那么苛刻,但是红黑树是二叉树,二叉就导致相同的数据量下高度更高、IO次数更多。
MyISAM与InnoDB 的区别
1. InnoDB支持事务,MyISAM不支持
2. InnoDB支持外键,而MyISAM不支持
3.InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。
MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
InnoDB的B+树主键索引的叶子节点就是数据文件,辅助索引的叶子节点是主键的值;而MyISAM的B+树主键索引和辅助索引的叶子节点都是数据文件的地址指针。
4.Innodb不支持全文索引,而MyISAM支持全文索引
5.InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而Myisam可以没有
如何选择:
1. 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;
2. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读也有写,请使用InnoDB。
InnoDB为什么推荐使用自增ID作为主键?
答:自增ID可以保证每次插入时B+索引是从右边扩展的,可以避免B+树和频繁合并和分裂(对比使用UUID)。如果使用字符串主键和随机主键,会使得数据随机插入,效率比较差。
索引的优点
提高查询效率
提高聚合函数查询效率
提高排序查询效率
使用覆盖索引避免回表
创建索引的策略
不要在NULL值列上使用索引,尽量使用NOT NULL约束列上使用索引
很少查询的字段不要使用索引
大数据类型字段不创建索引
使用索引时的注意事项
不要在条件NOT IN、<>、!= 等范围查询中使用索引
模糊查询时不要使用 %开头( 如 ‘%xxx’ , ‘%xxx%’)
查询索引的字段不要函数计算
联合索引查询时遵循最左原则
全部扫描超过30%不会走优化器;
读写分离-最大的作用就是缓解服务器的压力,主库处理事务性查询,从库处理select查询
好处:
- 缓解服务器的压力;增加机器的处理能力;
- 对于读应用较多的,应用读写分离是最好的,可以确保写的服务器压力更小,而读的服务器又可以接受点时间上的延迟。
CopyOnWrite 思想
如果有多个调用者(Callers)同时访问相同的资源(如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。
通俗易懂的讲,写入时复制技术就是不同进程在访问同一资源的时候,只有更新操作,才会去复制一份新的数据并更新替换,否则都是访问同一个资源。
mysql查询慢的原因和解决方案
1.没有索引或者没有用到索引
2.I/O吞吐量小,形成了瓶颈效应。
3.内存不足
4.网络速度慢
5.查询语句不好,没有优化