标签:唯一索引 流程 性能 nsa locking 级别 title 模式 tor
问题
问题1:mysql的存储引擎
问题2:mysql的索引机制
问题3:mysql的事务以及事务隔离级别
问题4:mvcc/GAP lock是做什么的
问题5:mysql的悲观锁与乐观锁
回答
mysql的存储引擎
mysql的常用存储引擎
mysql的索引机制有如下几种
备注:举例说明索引机制的使用场景(商城的会员卡系统,会员编号作为主键,会员编号就是唯一索引,用来创建B+树;会员姓名如果要创建索引,则就是普通索引;会员身份证信息如果要创建索引,则就是唯一索引)
补充知识:B+树与B树
(1.)B树
所谓的B树就是多路搜索树,任意一个非叶子节点最多有M个儿子,关键字分布在整颗树中,任何一个关键字出现且只出现一个节点中,搜索有可能在非叶子节点中结束,性能等价于二分查找,时间复杂度为O(lgN)
如:(M=3)
(2.)B+树
所谓的B+树,就是B树的变体,也是多路搜索树,非叶子节点的字数指针与关键字个数相同,非叶子节点子树指针指向子树,所有的叶子节点都增加一个链指针,所有的关键字都在叶子节点中出现,不可能在非叶子结点命中,非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层,比较适合文件索引系统
如:(M=3)
mysql的事务遵循4个条件(ACID),有原子性:不可分割性;一致性;隔离性;持久性;在实际使用中,使用事务保证一个事务中的操作,要么全部完成,要么全部不完成,保证数据的安全性
其中事务隔离级别分为以下几种
MVCC:既多版本并发操作,基本原理就是某个时间点的快照,每行数据都存在一个版本,每次数据更新时都更新该版本,修改是copy出当前版本随意修改,各个事务之间无干扰,保存时则比较版本号,如果成功,则覆盖原纪录,失败则放弃并回滚。需要注意的是mysql里的MVCC只解决读-写的阻塞问题,写-写依然还是阻塞的
GAP lock:间隙锁,用于解决mySQL中RR级别的幻读问题,如果一个事务操作的是一个区间的数据,会锁住这个区间所有的记录,即使这个记录不存在,这个时候另一个会话去插入这个区间的数据,就必须等待上一个结束。需要注意的是在此有可能会产生GAP死锁,例如下图
无论悲观锁和乐观锁都是并发控制主要采用的技术手段,都是为了保证数据库中的数据的完整性与一致性
悲观锁:对数据被外界修改持保守态度 (悲观),因此,在整个数据处理过程中,将数据处于锁定状态。 悲观锁的实现,往往依靠数据库提供的锁机制,而悲观锁一般流程如下
悲观锁主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载,还有会降低了并行性。
要使用悲观锁,我们必须关闭 mysql 数据库的自动提交属性,因为 MySQL 默认使用 autocommit 模式,也就是说,当你执行一个更新操作后,MySQL 会立刻将结果进行提交。 set autocommit=0; //1.开始事务 begin;/begin work;/start transaction; (三者选一就可以) //2.查询出商品信息 select status from t_goods where id=1 for update; //3.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1); //4.修改商品status为2 update t_goods set status=2; //5.提交事务 commit;/commit work; 上面的查询语句中,我们使用了 select…for update 的方式,这样就通过开启排他锁的方式实现了悲观锁。此时在 t_goods 表中,id 为 1 的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行。这样我们可以保证当前的数据不会被其它事务修改。 上面我们提到,使用 select…for update 会把数据给锁住,不过我们需要注意一些锁的级别,MySQL InnoDB 默认行级锁。行级锁都是基于索引的,如果一条 SQL 语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。
乐观锁:假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
数据库表设计 task 表有三个字段,分别是 id,value、version 实现 1. 先读 task 表的数据(实际上这个表只有一条记录),得到 version 的值为 versionValue 2. 每次更新 task 表中的 value 字段时,为了防止发生冲突,需要这样操作 update task set value = newValue,version = versionValue + 1 where version = versionValue; 只有这条语句执行了,才表明本次更新 value 字段的值成功 如假设有两个节点 A 和 B 都要更新 task 表中的 value 字段值,差不多在同一时刻,A 节点和 B 节点从 task 表中读到的 version 值为 2,那么 A 节点和 B 节点在更新 value 字段值的时候,都操作 update task set value = newValue,version = 3 where version = 2; 实际上只有 1 个节点执行该 SQL 语句成功,假设 A 节点执行成功,那么此时 task 表的 version 字段的值是 3,B 节点再操作 update task set value = newValue,version = 3 where version = 2; 这条 SQL 语句是不执行的,这样就保证了更新 task 表时不发生冲突。
问题:
问题1:MongoDB的存储引擎以及底层存储机制
问题2:MongoDB的版本变迁既特性
回答:
问题1:
存储引擎如下:
底层存储机制:空间局部性原理,B树
问题2:
MongoDB 3.0特性(2015年):顺序写入:LSM Tree结构,随机写入转换为顺序写入,速度稳定:和WiredTiger相比,写速度稳定
MongoDB 4.0特性(2018年6月):多文档事务支持,4.2版本开始支持分片集群分布式事务
问题:
问题1:redis支持的数据类型常用使用场景
问题2:redis的存储机制以及常用集群
回答
问题1:
redis支持的数据类型主要有string,list,set,zset,hash
redis的常用使用场景
问题2:
redis的存储机制有
常用集群方式有
ok
标签:唯一索引 流程 性能 nsa locking 级别 title 模式 tor
原文地址:https://www.cnblogs.com/gbq-dog/p/11080558.html