数据库问题总结

                                                                        数据库总结

1.数据库的四大特性
数据库的四大特性:原子性,一致性、隔离性、持久性。
原子性:在事务包含的所有操作要么同时执行成功,要么同时失败并回滚,因此事务操作如果成功就必须要完全应用到数据库,如果失败则不能对数据库有任何影响。
一致性:指的是事务对数据库操作前后,数据库的整体约束性没有被破坏。比如,A向B转账,不可能A扣了钱但是B确没有到账。
隔离性:是指当多个用户并发访问数据库时,比如同时操作一张表时,数据库为每一个用户开启的事务,并不会被其他的事务所干扰,多个并发事务之间要相互隔离。
持久性:只一旦事务被提交后,那么对数据库的改变将会是永久的

2.事务的并发?事务隔离级别,每个级别会引发什么问题,MYSQL默认是哪个级别?
首先,从理论上来说的话,事务应该彼此完全隔离,以避免并发事务所导致的问题,但是这样会对性能产生很大的影响,因此在实际的开发过程中,为了提升性能,一般会采用较低的隔离级别,隔离级别可以通过事务属系指定。
再说一下事务在并发运行的过程中会导致哪些问题:
1.脏读:事务A读取了事务B更改的数据,但是事务B回滚了,那么事务A就读取了事务B更改但未提交的数据,那么A读取的数据就为脏数据。
2.不可重复度:事务A在多次读取同一数据时,事务B对这一数据更改并提交,导致事务A多次多次读取同一数据时,结果会因B事务的更改会导致两次读取的数据不一致。
3.幻读:幻读解决了不可重复读,保证了同一个事务里,查询的结果都是从事务开始时的状态。
例如:事务T1对一个表中的说有行的某个数据从1改为了2,但是之后,事务T2又对这个表插入了一个数据项,并且数值也是1,并且提交给了数据库,那么当事务1的用户查看刚刚修改后的数据,会发现T2事务插入的那行还是1,就像是发生了幻觉一样,这就产生了幻读。
解决不可重复读的问题就是:锁住满足条件的行
解决幻读的问题:锁住表

事务的隔离级别有四种:读未提交,不可重复读,可重复读,串行化。

事务的隔离级别 脏读 不可重复读 幻读
读未提交 是 是 是
不可重复读 否 是 是
可重复读 否 否 是
串行化 否 否 否

读未提交:另一个事务修改了数据,但尚未提交,而本事务的select语句会读取到这些未被提交的数据,从而发生了脏读。
不可重复读:事务A在多次读取统一数据时,事务B在事务A读取过程中,对数据做出了更改并提交,导致事务A多次读取统一数据时,前后两次读取的结果会不一致。
可重复读:在同一个事务里,select的结果是事务开始时执行的状态,因此同样的select操作读取到的结果会不一致,会有幻读现象。
串行化: 最高的隔离级别,在这个隔离级别下,不会有任何的异常产生,并发的事务,事务是一个一个按照顺序执行的。

MYSQL默认的隔离级别: 可重复读。

事务的隔离级别:读未提交:写数据会锁住相应的行
可重复读:写数据会锁住整张表
串行化:读写数据都会锁住整张表。

总结:隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,所以对于大多数程序来说,可以优先考虑将数据库的隔离级别设置成可重复读,既能避免脏读,同时也能保证并发效率,虽然会幻读等一些的并发问题,所以在个别的场合下,可以采用悲观锁和乐观锁来控制。

3.为什么数据库的索引采用B+TREE索引而不是hash索引?
首先对于hash索引来说:仅仅能够满足等值查询,并不能满足范围查询,因为经过相应的hash算法处理之后的hash值的大小关系,并不能保证和运算前完全一样

那么介绍一下hash算法:


clipboard.png

如图所示:当索引进来首先会计算hash码,然后散列到各个对应的数组位置,但是当出现hash冲突时,会插入在链表的头部(jdk1.7).

所以在数据库不采用hash索引是因为虽然能后处理等职查询,但是在处理范围查询等一些情况时毫无用武之地,另外如果hash索引遭遇到大量的hash冲突会导致链表过长或红黑树过高,则其索引性能不一定必b+tree高。

最重要的是如何去理解b+tree索引:


clipboard.png

对于这张图:首先innodb有一个页的概念。数据库存储的数据被依次放在页里面
页里面包含目录 目录里面包含真实的数据。
如上图第100页里面存储了4条数据,第一条和第二条存储在目录1里面,第3条和第四条存储在目录4里面。第200页同理。
那么在这个时候我需要找3-322c这行数据时就需要先找到页码,在去目录里面找到对应的数据。
如果有更多的数据进来就会有更多的页码。


clipboard.png

那么就会出现索引页,因为最底层其实存放的是数据页。数据页里面存放的就是每一页的开头。

同理,当数据还在增多时就像下图


clipboard.png

最终的b+tree就是这样来存储数据的(以上都是按照主键来进行的)

那么这么说来b+tree的好处究竟在哪里呢?
首先索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数,提升索引效率。
磁盘存取原理:
    索引一般以文件形式存储在磁盘上,索引检索需要磁盘I/O操作。与主存不同,磁盘I/O存在机械运动耗费,因此磁盘I/O的时间消耗是巨大的。
所以:
1.B+Tree 单个节点能放多个子节点,相同IO次数,检索出更多信息。
2.B+TREE 只在叶子节点存储数据 & 所有叶子结点包含一个链指针 & 其他内层非叶子节点只存储索引数据。只利用索引快速定位数据索引范围,先定位索引再通过索引高效快速定位数据。

4.有哪些锁?
悲观锁:悲观锁的特点是先获取锁,再进行业务操作。即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁了再进行业务操作。通常来讲在数据库上的悲观锁需要数据库本身提高支持,即通常用的select...for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行的则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update 获取锁的行锁会在事务结束时自动释放,因此必须在事务中使用。
另外,MYSQL还有个问题时select for update 语句执行中所有的扫描过的行都会被锁上,这一点容易造成问题。因此如果在mysql中用悲观锁务必要确定索引,而不是全表扫描。
乐观锁: 也叫乐观控制并发,它假设多用户并发的事务在处理时并不会相互影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚。
乐观锁的特点是先进行业务操作,不到万不得已不去拿锁。即乐观的认为拿锁多半会成功,因此在进行完业务操作需要进行实际更新数据的最后一步再去拿一下锁就好。
乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是需要锁的数据上增加一个版本号,或者时间戳。
给表加版本号,是数据库实现乐观锁的一种方式。

对比:乐观锁在不发生取锁失败的情况下比悲观锁开销小,但是一旦取锁失败则回滚那么开销比较大。乐观锁和悲观锁是数据库用来保证数据并发安全防止更新丢失的两种方法

5.mysql的mvcc机制
MVCC,就是多版本控制。MVCC是一种并发控制的方法,一般再数据库管理系统中,实现对数据库的并发访问。
在mysql的innodb引擎就是值在读已提交和可重复读这两种隔离级别下的事务对于select操作会访问版本链中的记录的过程。
所以,这就使得别的事务可以修改这条记录,反正每次修改都会在版本链中记录。select可以去版本链中拿记录,这就实现了读-写,写-读的并发执行,提升了系统的性能。
下面具体看看到底是如何实现的。

首先了解何为版本链?
在innodb存储引擎中,它的每条记录中必须有两个必要的隐藏列。
trx_id: 这个id用来存储每次对某条记录进行修改时的事务id。
roll_pointer:每次对记录有修改的时候,都会把老的版本写入undo日志中。这个roll_pointer就是存储一个指针,它指向这个记录上一个老版本的位置,通过它来获得上一个老版本的信息。


clipboard.png

比如现在有个事务id为60的执行这条记录的修改语句


clipboard.png

此时在undo日志中就存在版本链
clipboard.png

再说一个比较重要的概念:ReadView
首先对于读已提交和可重复读这两种隔离级别他们生成ReadView的策略不同

先介绍一下ReadView. ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是begin了但是还未提交的事务。通过这个列表来判断记录的某个版本是否对于当前事务可见。
假设当前列表里的事务id为【80,100】
这时如果你要访问的记录版本的事务id为50,比当前的列表最小的id80小,那说明这个事务在之前就提交了,所以对当前活动的事务来说是可以访问的。
但是如果你要访问的事务id为80-100之间,那么就要再判断一下是否在列表内,如果在那么就说明此事务还未提交,所以版本并不能被访问。如果不在那说明事务已经被提交了,所以版本可以被访问。
但是如果你要访问的事务id=110,那么此本版比100还要大,那说明这个版本是在ReadView生成之后才发生的,所以不能被访问。
这些记录都是在版本链里面去找,先找最佳的记录,如果最近的这条记录不符合条件的话,即不可见,再去上一个版本再比较当前事务的id和这个版本的事务id能不能被访问,以此类推直到返回可见版本或者结束。

举例说明一下:
在读已提交的隔离级别下:
比如此时有一个事务id为100的事务,修改了name,使得name等于小明2,但是事务还没提交。则此时的版本链为:


clipboard.png

那此时另一个事务发起了select语句要查询id为1的记录,那此时生成的ReadView列表只有【100】,那就应该去版本链里面去找了,首先肯定找最近一条,发现事务id为100,也就是那么为小明2的那条记录,在列表内,故不能访问。
这个时候就要通过指针继续去找下一条,name为小明1的记录,

,小于列表的最小事务id100,所以可以访问,直接访问结果为小明1.
那这时候我们把事务id为100的事务提交了,并且新建了一个事务id为110也修改了1的记录,并且也不提交事务。


clipboard.png

这个时候的版本链为:
clipboard.png

这时候之前那个select事务又执行了一次查询,要查询id=1的记录。
这时关键的地方就来了。
如果你设置的是读已提交的隔离级别,这个时候就会重新生成一个ReadView,那么列表里面的值就变成110.
按照上面的说法,你去版本链里面通过事务id对比查找找打最合适的结果就是小明2.

可是,
如果你设置的是可重复读的隔离级别,这个时候你的select事务的ReadView还是第一次select时候生成的ReadView,也就是【100】,所以select查询的结果还是小明1,所以第二次和第一次的结果一样,所以叫可重复读。
也就是说已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。
这就是mysql的MVCC,通过版本链,实现多版本,可并发读-写,写-读,通过ReadView生成的策略的不同实现不同的隔离级别。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335