文章目录
1. MyISAM和InnoDB关于锁方面的区别?
- MyISAM默认使用表级锁,不支持行级锁;
- InnoDB默认用的行级锁,也支持表级锁。
- 无论是表锁还是行锁,均分为共享锁share lock(S)和排它锁exclusive lock(X)。
1.1 MyISAM
- MyISAM先上读锁后上写锁(被Block)、读锁(不被Block)
- MyISAM对数据进行select时,自动加上一个表级读锁,表级锁自动锁住整张表;对数据进行增删改时,操作表加上一个表级别的写锁。读锁未被释放时,另外一个Session(数据库客户端一个窗口tab就是一个Session)想要对该表加上一个写锁就会被阻塞(Block),直到所有的读锁都被释放为止。
- 显示给表加上读锁:
lock table 表名 read;
- 释放锁:
unlock tables;
- 读锁也叫共享锁(S锁),因为在进行范围查询时依然能对表里的数据进行读操作。
- MyISAM先上写锁后上读锁(被Block)、写锁(被Block)
- 当上了写锁在上读锁时,需要等待写锁的释放。上写锁的同时再上写锁,也被阻塞。所以写锁也叫排它锁(X锁)。
- 上共享锁后依然支持上共享锁,上排它锁后共享锁和排它锁都不支持。
- 除了可以对insert、update、delete语句上排它锁,也可以对select语句上排它锁。在语句后面加上for update。
适合场景:
- 频繁执行全表count语句
- 对数据进行增删改的频率不高,查询非常频繁
- 没有事务
1.2 InnoDB
- InnoDB用的二段锁,即加锁和解锁是分成两个步骤。先对同一个事务里的一批操作进行加锁,commit后再对事务加上的锁进行统一的解锁。
- MySQL自动提交事务,即commit是自动提交的。
- InnoDB在SQL没用到索引时走的是表级锁,用到索引时走的时行级锁和gap锁。(行级锁,需要行扫描,代价比较大)
- InnoDB的锁默认支持行级锁。
- InnoDB对select进行了改进,在select语句后面加lock in share mode显示上读锁,才不可以上写锁。可以上共享锁。
- InnoDB除了支持行级锁外,还支持表级意向锁,意向锁分为意向共享锁IS、意向排它锁IX,作用是在进行表级别操作时不用轮询每一行看有没有上行锁。
适合场景:
- 对数据进行增删改的频率频繁
- 可靠性要求高,要求支持事务
1.3 数据库锁的分类
- 按锁的粒度划分,可以分为表级锁、行级锁、页级锁。(BDB引擎使用页级锁,介于表级锁和行级锁,锁定位于同一个存储页的相邻几行数据)
- 按锁级别划分,可分为共享锁和排它锁。
- 按加锁方式划分,可分为自动锁、显式锁。
- 按操作划分,可分为DML锁、DDL锁。
- 按使用方式划分,可分为乐观锁、悲观锁。
- 悲观锁对外界的修改持保守态度,外界指即本系统当前的其他事务和外部系统的事务处理。
- 全程用排它锁锁定是悲观锁的一种实现。
- 悲观并发控制是先取锁再访问的保守策略,对数据处理的安全提供了保证。
- 在效率方面处理加锁的机制会产生额外的开销,增加产生死锁的机会;
-
- 乐观锁认为数据一般情况不会造成冲突,数据提交更新时才会对数据的冲突与否进行检测,发现冲突返回用户错误的信息,让用户决定如何去做。
- 相对悲观锁对数据进行处理时,乐观锁不会使用事务的锁机制,
- 一般实现乐观锁的方式是记录数据版本。
- 实现数据版本有两种方式:第一种是使用版本号;第二种是使用时间戳)
2. 数据库事务的四大特性
ACID
- A -->原子性(Atomic):事务包含的所有操作要莫全部执行,要么全部失败回滚。要么全做,要么全不做。
- C–>一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另外一个一致的状态。以转账为例,A账户+B账户=2000,无论A和B如何转账,转几次账,A和B的钱加起来还是2000。
- I–>隔离性(Isolation):多个事务并发执行时一个事务的执行不影响其他事务的执行。下面的知识点是对隔离性的深入研究。
- D–>持久性(Durability):一个事务一旦提交,对数据库的修改永久保存在数据库中。当系统或者介质发生故障时确保已提交事务的更新不能丢失,即对已提交事务的更新能恢复。一旦一个事务被提交,DBMS保证提供适当冗余,使其耐得住系统的故障。
3. 事务隔离级别以及各级别下的并发访问问题?
事务并发访问引起的问题以及如何避免?
更新丢失
–MySQL所有事务隔离级别在数据库层面上均可避免脏读
(一个事务读到另一个事务未提交的数据)–Read-Committed即RC事务隔离级别以上可以避免(Read-Committed规定事务只能读取其他事务已经提交的数据,不允许读未提交的数据)
查询当前Session的事务隔离级别:select @@tx_isolation;
设置当前Session的事务隔离级别为read uncommitted:set session transaction isolation level read uncommitted;
不可重复读
(事务A多次读取同一数据,事务B在事务A读取数据时对数据更新并提交,导致事务A多次读取数据时数据不一致)--Repeatable-Read
即RR事务隔离级别以上可以避免幻读
(事务A读取与搜索条件相匹配的若干行,事务B以插入或删除行的方式来修改事务A的结果集,导致事务A看起来像出现幻觉一样)–Serializable事务隔离级别可避免- 不可重复读侧重于对同一数据的修改,幻读侧重于新增或删除。
- 事务隔离级别越高,安全性越高,串行化执行越严重,降低数据的并发度。根据业务的需要设置事务的隔离级别。Oracle默认为Read-Committed,MySQL默认为Repeatable-Read。
4. InnoDB可重复读隔离级别下如何避免幻读?
表象:在RR级别下,基于伪MVCC(多版本并发控制,读不加锁,读写不冲突)实现的快照读(非阻塞读)来避免使我们看到幻行
内在:next-key锁(行锁+gap锁)
当前读
:select…lock in share mode、select…for update、update、delete、insert。加了锁的增删改查语句,不管是共享锁还是排它锁。读取的是记录的最新版本,读取之后还需要保证其他并发事务不能修改当前记录,对读取的记录加锁,所以叫当前读。除了select…lock in share mode对记录加共享锁,其他都加排它锁。快照读
:不加锁的非阻塞读,select。不加锁是在事务隔离级别不为Serializable的前提下。在Serializable下,由于是串行读,快照读退化成当前读,即select…lock in share mode。快照读是为了提升并发性能,快照读的实现是基于多版本并发控制即MVCC,MVCC是行级锁的一个变种,在很多情况下避免了加锁操作,因此开销更低。基于多版本意味着快照读读到的不一定是数据的最新版本,可能是历史版本。- 为什么update、delete、insert也是当前读? RDMS关系型数据库管理系统由两部分组成,程序实例和存储InnoDB,如图。update操作内部包含一个当前读来获取数据的最新版本。
5. RC、RR级别下的InnoDB的非阻塞读如何实现?(MVCC)
https://www.jianshu.com/p/8845ddca3b23
- 数据行里DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段
- DB_TRX_ID字段标识最近一次对本行记录做修改,不管是insert或update,事务的标识符,即最后一次修改本行记录的事务的ID。
- DB_ROLL_PTR回滚指针,写入回滚段Rollback segment的undo日志记录,如果一行记录被更新,undo log report包含重建该行记录被更新之前内容所必须的信息。
- DB_ROW_ID行号,包含一个随着新行插入而单调递增的行id,由innoDB自动产生聚集索引时,聚集索引会包含行id的值,否则行id不会出现在任何索引中。InnoDB的表即没有主键也没有唯一键时,InnoDB会自动隐式创建一个的自动递增隐藏主键字段,即DB_ROW_ID。
- 光有这三个字段不足以实现快照读,还需要
undo日志
。当对记录做了变更操作时,就会成undo记录。undo记录存储的是老版数据,当一个旧事务需要读取数据时,为了读取老版数据,需要顺着undo链找到满足其可见性的记录。undo log主要分为两种,insert undo log和update undo log,insert undo log表示事务对insert新纪录产生的undo log,只在事务回滚时需要,事务提交后就可以立即丢弃。update undo log是事务在对数据delete、update时产生的undo log,不仅在事务回滚时需要,快照读也需要,所以不能随便删除。只有当数据库使用的快照不涉及该日志记录,对应的回滚日志才会被线程删除。
6 .MyISAM和InnoDB引擎区别
- 存储结构(主索引/辅助索引)
- InnoDB的数据文件本身就是主索引文件。而MyISAM的主索引和数据是分开的。
- InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别。
- InnoDB是聚簇索引,数据挂在主键索引之下。
- 锁
- MyISAM使用的是表锁;InnoDB使用行锁
- 事务
- MyISAM没有事务支持和MVCC;InnoDB支持事务和MVCC
- 全文索引
- MyISAM支持FULLTEXT类型的全文索引;InnoDB不支持FULLTEXT类型的全文索引,但是InnoDB可以使用sphinx插件支持全文索引,并且效果更好。
- 主键
- MyISAM允许没有任何索引和主键的表存在,索引都是保存行的地址;InnoDB如果没有设定主键或非空唯一索引,就会自动生成一个6字节的主键,数据是主索引的一部分,附加索引保存的是主索引的值。
- 外键
- MyISAM不支持;InnoDB支持