-
- 索引是什么?有什么作用以及优缺点?
- 什么是事务?
- Spring事务的7种传播级别
- 什么是嵌套事务?
- Spring事务的注解配置
- 在同一个类中一个普通方法调用另一个有@Transcational注解的方法时,Spring事务管理还启作用吗?
- 数据库的乐观锁和悲观锁是什么?
- 说一说drop、delete与truncate的区别
- 什么是内联接、左外联接、右外联接?
- order by, group by, having的作用
- 数据隔离级别
- Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?
- #{}和${}的区别是什么?
- MyBatis与Hibernate有哪些不同?
- MyBatis的好处是什么?
- 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?
- 什么是MyBatis的接口绑定,有什么好处?
- 什么情况下用注解绑定,什么情况下用xml绑定?
- 当实体类中的属性名和表中的字段名不一样,如果将查询的结果封装到指定pojo?
- Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
- Mybatis中如何执行批处理?
- 在mapper中如何传递多个参数?
- resultType resultMap的区别?
- 如果有很多数据插入MYSQL 你会选择什么方式?
- 索引具体采用的哪种数据结构呢?
- InnoDB使用的B+ 树的索引模型,你知道为什么采用B+ 树吗?这和Hash索引比较起来有什么优缺点吗?
- B+ Tree的叶子节点都可以存哪些东西吗?
- MySQL的回表查询,是什么意思?
- 覆盖索引是什么意思?
- 在创建索引的时候都会考虑哪些因素呢?
- 有时候创建了索引,但执行的时候并没有使用这个索引呢?
- 事务四大特性,以及事务的二段提交机制?
- 数据库万级变成亿级,怎么处理?
- MySQL 性能优化策略
- MySQL的基本操作 主从数据库一致性维护
- mysql的优化策略有哪些
- mysql索引的实现 B+树的实现原理
- 什么情况索引不会命中,会造成全表扫描
索引是对数据库表中一或多个列的值进行排序的结构, 索引就是加快检索表中数据的方法。
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
- PROPAGATION_REQUIRED ,默认的spring事务传播级别
使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。
- PROPAGATION_SUPPORTS
该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。
- PROPAGATION_MANDATORY
该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!
- PROPAGATION_REQUIRES_NEW
该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行
这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。
- PROPAGATION_NOT_SUPPORTED
当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务, 可以帮助你将事务极可能的缩小。
- PROPAGATION_NEVER
该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!
- PROPAGATION_NESTED
该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
嵌套是子事务套在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。重点就在于那个save point:
- 如果子事务回滚,会发生什么?
父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。
- 如果父事务回滚,会发生什么?
父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分。
- 把一个DataSource(如DruidDataSource)作为一个@Bean注册到Spring容器中,配置好事务性资源。
- 把一个@EnableTransactionManagement注解放到一个@Configuration类上,配置好事务管理器,并启用事务管理。
- 把一个@Transactional注解放到类上或方法上,可以设置注解的属性,表明该方法按配置好的属性参与到事务中。
- 如何配置回滚异常
使用@Transactional注解的rollbackFor/rollbackForClassName属性,可以精确配置导致回滚的异常类型,包括checked exceptions。
noRollbackFor/noRollbackForClassName属性,可以配置不导致回滚的异常类型,当遇到这样的未处理异常时,照样提交相关事务。
- 事务注解在类/方法上
@Transactional注解既可以标注在类上,也可以标注在方法上。当在类上时,默认应用到类里的所有方法。如果此时方法上也标注了,则方法上的优先级高。
- 事务注解在类上的继承性
@Transactional注解的作用可以传播到子类,即如果父类标了子类就不用标了。但倒过来就不行了。
- 事务注解在接口/类上
@Transactional注解可以用在接口上,也可以在类上。在接口上时,必须使用基于接口的代理才行,即JDK动态代理。
事实是Java的注解不能从接口继承,如果你使用基于类的代理,即CGLIB,或基于织入方面,即AspectJ,事务设置不会被代理和织入基础设施认出来,目标对象不会被包装到一个事务代理中。
Spring团队建议注解标注在类上而非接口上。
答案是不会起作用的。此处的this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强
乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
- 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
- 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
- 速度,一般来说: drop> truncate >delete
- delete和truncate只删除表的数据不删除表的结构
- delete语句是dml,这个操作会放到rollback segement中,事务提交之后才生效
- Serializable
最严格的级别,事务串行执行,资源消耗最大
- REPEATABLE READ
保证一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
- READ COMMITTED
大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
- Read Uncommitted
保证了读取过程中不会读取到非法数据。
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
Serializable | 不会 | 不会 | 不会 |
REPEATABLE READ | 不会 | 不会 | 会 |
READ COMMITTED | 不会 | 会 | 会 |
Read Uncommitted | 会 | 会 | 会 |
- Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
- Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。
- 其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
- #{}是预编译处理,${}是字符串替换。
- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
- Mybatis在处理时,就是把时,就是把{}替换成变量的值。
- 使用#{}可以有效的防止SQL注入,提高系统安全性。
Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。
- 在Xml映射文件中,标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。
- 标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。
- 每一个、、、标签均会被解析为MappedStatement对象,标签内的sql会被解析为BoundSql对象。 什么是MyBatis的接口绑定,有什么好处? 什么情况下用注解绑定,什么情况下用xml绑定? 当实体类中的属性名和表中的字段名不一样,如果将查询的结果封装到指定pojo? 通过在查询的sql语句中定义字段名的别名。 通过来映射字段名和实体类属性名的一一对应的关系。 Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复? 不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复 Mybatis中如何执行批处理? 使用BatchExecutor完成批处理。 在mapper中如何传递多个参数? 直接在方法中传递参数,xml文件用#{0} #{1}来获取 使用 @param 注解:这样可以直接在xml文件中通过#{name}来获取 resultType resultMap的区别? 类的名字和数据库相同时,可以直接设置resultType参数为Pojo类 若不同,需要设置resultMap 将结果名字和Pojo名字进行转换 如果有很多数据插入MYSQL 你会选择什么方式? 索引具体采用的哪种数据结构呢? MySQL主要有两种结构:Hash索引和B+ Tree索引; InnoDB引擎,默认的是B+树。 InnoDB使用的B+ 树的索引模型,你知道为什么采用B+ 树吗?这和Hash索引比较起来有什么优缺点吗? B+ 树是一种多路平衡查询树,B+Tree索引和Hash索引区别? 哈希索引适合等值查询,但是无法进行范围查询; 哈希索引没办法利用索引完成排序 ; 哈希索引不支持多列联合索引的最左匹配规则; 如果有大量重复键值的情况下,哈希索引的效率会很低,因为存在哈希碰撞问题。 B+ Tree的叶子节点都可以存哪些东西吗? InnoDB的B+ Tree可能存储的是整行数据,也有可能是主键的值。 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引。 聚集索引,表中存储的数据按照索引的顺序存储,检索效率比普通索引高,但对数据新增/修改/删除的影响比较大 非聚集索引,不影响表中的数据存储顺序,检索效率比聚集索引低,对数据新增/修改/删除的影响很小 聚簇索引与非聚簇索引的区别 MySQL的回表查询,是什么意思? MySQL中的回表查询是二级索引无法直接查询所有列的数据,通过二级索引查询到聚簇索引后,再查询到想要的数据,这种通过二级索引查询出来的过程,就叫做回表。 这样理解对吗? 如果explain查看执行计划,在使用了索引,且Extra是Using where的情况下,表示回表查询数据。 覆盖索引是什么意思? 覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。 当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。 如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。 当我们通过SQL语句:select key2 from covering_index_sample where key1 = 'keytest';的时候,就可以通过覆盖索引查询,无需回表。 在创建索引的时候都会考虑哪些因素呢? 字段区分度 联合索引(最左前缀匹配) 有时候创建了索引,但执行的时候并没有使用这个索引呢? 一条SQL语句的查询,可以有不同的执行方案,至于最终选择哪种方案,需要通过优化器进行选择,选择执行成本最低的方案。优化过程大致如下: 根据搜索条件,找出所有可能使用的索引; 计算全表扫描的代价; 计算使用不同索引执行查询的代价; 对比各种执行方案的代价,找出成本最低的那一个。 事务四大特性,以及事务的二段提交机制? 数据库万级变成亿级,怎么处理? MySQL 性能优化策略 为查询缓存优化你的查询, 像 NOW() 和 RAND() 或是其它的诸如此类的 SQL 函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的 当只要一行数据时使用 LIMIT 1 为搜索字段建索引 在 Join 表的时候使用相同类型的字段,并将其索引 千万不要 ORDER BY RAND() 避 免 SELECT * 使用 ENUM 而不是 VARCHAR ENUM 类型是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来做一些选项列表变得相当的完美。 尽可能的使用 NOT NULL定义 Prepared Statements 把 IP 地址存成 UNSIGNED INT 只需要 4 个字节 尤其是当你需要使用这样的 WHERE 条件:IP between ip1 and ip2 固定长度的表会更快 如果表中的所有字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length” 垂直分割 样可以降低表的复杂度和字段的数目,从而达到优化的目的。 拆分大的 DELETE 或 INSERT 语句 越小的列会越快 MySQL的基本操作 主从数据库一致性维护 mysql的优化策略有哪些 mysql索引的实现 B+树的实现原理 什么情况索引不会命中,会造成全表扫描 数据库表设计原则 1、数据库设计的三大范式:为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。第一范式(确保每列保持原子性);第二范式(确保表中的每列都和主键相关);第三范式(确保每列都和主键列直接相关,而不是间接相关)。 2、不应该针对整个系统进行数据库设计,而应该根据系统架构中的组件划分,并且一个对象有且只有一项职责,如果一个对象要负责两个或两个以上的职责,应进行分拆。 3、根据建立的领域模型进行数据库表的映射,此时应参考数据库设计第二范式:一个表中的所有非关键字属性都依赖于整个关键字 4、数据库表结构设计从一开始即满足第三范式:一个表应满足第二范式,且属性间不存在传递依赖。 5、如果表结构中存在多值依赖,则证明领域模型中的对象具有至少两个以上的职责,应根据第一条进行设计修正。第四范式:一个表如果满足BCNF,不应存在多值依赖。 6、表和表之间的关联尽量采用弱关联以便于对表字段和表结构的调整和重构 7、应针对所有表的主键和外键建立索引,有针对性的(针对一些大数据量和常用检索方式)建立组合属性的索引,提高检索效率 MySQL索引结构 这里有一个很重要的一点就是 B+ 树的非叶子节点不保存数据,只有索引。一棵 m 阶的 B+ 树和 m 阶的 B 树的异同点在于: 节点的子树数和关键字数相同(B 树是关键字数比子树数少一); 所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针(节点的关键字表示的是子树中的最大数,在子树中同样含有这个数据),且叶子结点本身依关键字的大小自小而大的顺序链接。 (而 B 树的叶子节点并没有包括全部需要查找的信息); 所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而 B 树的非终节点也包含需要查找的有效信息)。 叶子节点之间通过指针连接。 数据库回表 对于主键索引和非主键索引,使用的数据结构都是 B+Tree,唯一的区别在于叶子结点中存储的内容不同: 主键索引的叶子结点存储的是一行完整的数据。 非主键索引的叶子结点存储的则是主键值。 这就是两者最大的区别。 所以,当我们需要查询的时候: 如果是通过主键索引来查询数据,例如 select * from user where id=100,那么此时只需要搜索主键索引的 B+Tree 就可以找到数据。 如果是通过非主键索引来查询数据,例如 select * from user where username='javaboy',那么此时需要先搜索 username 这一列索引的 B+Tree,搜索完成后得到主键的值,然后再去搜索主键索引的 B+Tree,就可以获取到一行完整的数据。 对于第二种查询方式而言,一共搜索了两棵 B+Tree,第一次搜索 B+Tree 拿到主键值后再去搜索主键索引的 B+Tree,这个过程就是所谓的回表。 索引的实现原理 在MySQL中,索引是在存储引擎层实现的,不同存储引擎对索引的实现方式是不同的,下面我们探讨一下MyISAM和InnoDB两个存储引擎的索引实现方式。 MyISAM索引实现:MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。 InnoDB索引实现:虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。第一个重大区别是InnoDB的数据文件本身就是索引文件。MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。 第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。 MyISAM与InnoDB 的区别 InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务; InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败; InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。 MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。 也就是说:InnoDB的B+树主键索引的叶子节点就是数据文件,辅助索引的叶子节点是主键的值;而MyISAM的B+树主键索引和辅助索引的叶子节点都是数据文件的地址指针。 什么是MVCC 全称Multi-Version Concurrency Control,即多版本并发控制,主要是为了提高数据库的并发性能。以下文章都是围绕InnoDB引擎来讲,因为myIsam不支持事务。 MVCC解决并发哪些问题? mvcc用来解决读—写冲突的无锁并发控制,就是为事务分配单向增长的时间戳。为每个数据修改保存一个版本,版本与事务时间戳`相关MVCC解决并发哪些问题? mvcc用来解决读—写冲突的无锁并发控制,就是为事务分配单向增长的时间戳。为每个数据修改保存一个版本,版本与事务时间戳相关联。 读操作只读取该事务开始前的数据库快照。 解决问题如下: 并发读-写时:可以做到读操作不阻塞写操作,同时写操作也不会阻塞读操作。 解决脏读、幻读、不可重复读等事务隔离问题,但不能解决上面的写-写 更新丢失问题。 因此有了下面提高并发性能的组合拳: MVCC + 悲观锁:MVCC解决读写冲突,悲观锁解决写写冲突 MVCC + 乐观锁:MVCC解决读写冲突,乐观锁解决写写冲突 MVCC的实现原理 它的实现原理主要是版本链,undo日志 ,Read View 来实现的 MySQL的索引为什么用B+树? 相对于二叉树,层级更少,搜索效率高 对于 B-Tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针也跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低 相对于 Hash 索引,B+Tree 支持范围匹配及排序操作 B+树由B树和索引顺序访问方法演化而来,它是为磁盘或其他直接存取辅助设备设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶子节点,各叶子节点通过指针进行链接。 B+树索引在数据库中的一个特点就是高扇出性,例如在InnoDB存储引擎中,每个页的大小为16KB。在数据库中,B+树的高度一般都在2~4层,这意味着查找某一键值最多只需要2到4次IO操作,这还不错。因为现在一般的磁盘每秒至少可以做100次IO操作,2~4次的IO操作意味着查询时间只需0.02~0.04秒。 MySQL的B+树索引为什么只需要2-4层? 假设数据库中一条记录是 1KB,那么一个页就可以存 16 条数据(叶子结点);对于非叶子结点存储的则是主键值+指针,在 InnoDB 中,一个指针的大小是 6 个字节,假设我们的主键是 bigint ,那么主键占 8 个字节,当然还有其他一些头信息也会占用字节我们这里就不考虑了,我们大概算一下,小伙伴们心里有数即可: 16*1024/(8+6)=1170 即一个非叶子结点可以指向 1170 个页,那么一个三层的 B+Tree 可以存储的数据量为: 1170*1170*16=21902400 可以存储 2100万 条数据。 在 InnoDB 存储引擎中,B+Tree 的高度一般为 2-4 层,这就可以满足千万级的数据的存储,查找数据的时候,一次页的查找代表一次 IO,那我们通过主键索引查询的时候,其实最多只需要 2-4 次 IO 操作就可以了。 MySQL事务隔离级别 SQL 标准定义了四种隔离级别,这四种隔离级别分别是: 读未提交(READ UNCOMMITTED); 读提交 (READ COMMITTED); 可重复读 (REPEATABLE READ); 串行化 (SERIALIZABLE)。 事务隔离是为了解决脏读、不可重复读、幻读问题,上述4种隔离级别MySQL都支持,并且InnoDB存储引擎默认的支持隔离级别是REPEATABLE READ,但是与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ事务隔离级别下,使用Next-Key Lock的锁算法,因此避免了幻读的产生。所以,InnoDB存储引擎在默认的事务隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的SERIALIZABLE隔离级别。 MySQL 中RC和RR隔离级别的区别 RC 与 RR 在锁方面的区别 1> 显然 RR 支持 gap lock(next-key lock),而RC则没有gap lock。因为MySQL的RR需要gap lock来解决幻读问题。而RC隔离级别则是允许存在不可重复读和幻读的。所以RC的并发一般要好于RR; 2> RC 隔离级别,通过 where 条件过滤之后,不符合条件的记录上的行锁,会释放掉(虽然这里破坏了“两阶段加锁原则”);但是RR隔离级别,即使不符合where条件的记录,也不会是否行锁和gap lock;所以从锁方面来看,RC的并发应该要好于RR; RC 与 RR 在复制方面的区别 1> RC 隔离级别不支持 statement 格式的bin log,因为该格式的复制,会导致主从数据的不一致;只能使用 mixed 或者 row 格式的bin log; 这也是为什么MySQL默认使用RR隔离级别的原因。复制时,我们最好使用:binlog_format=row 5.3 RC 与 RR 在一致性读方面的区别 简单而且,RC隔离级别时,事务中的每一条select语句会读取到他自己执行时已经提交了的记录,也就是每一条select都有自己的一致性读ReadView; 而RR隔离级别时,事务中的一致性读的ReadView是以第一条select语句的运行时,作为本事务的一致性读snapshot的建立时间点的。只能读取该时间点之前已经提交的数据。 5.4 RC 支持半一致性读,RR不支持 RC隔离级别下的update语句,使用的是半一致性读(semi consistent);而RR隔离级别的update语句使用的是当前读;当前读会发生锁的阻塞。 脏读,不可重复读,幻读 脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读。 不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。 幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。 MySQL 中有哪几种锁 一、按照对数据操作的锁粒度来分:行级锁、表级锁、页级锁、间隙锁 1 行级锁 2 表级锁 3 页级锁 二、按照锁的共享策略来分:共享锁、排他锁、意向共享锁、意向排他锁 innodb的意向锁有什么作用? 三、从加锁策略上分:乐观锁和悲观锁 四、其他:自增锁 自增锁(AUTO-INC锁) 外键检测的加锁策略 API接口安全性设计 1. Token授权机制 2. 时间戳超时机制 3. API签名机制 API接口签名生成算法 主要步骤如下: (1)将所有业务请求参数按字母先后顺序排序。 (2)参数名称和参数值链接成一个字符串A。 (3)在字符串A的首尾加上apiSecret接口密匙组成一个新字符串B。 (4)对字符串进行MD5散列运算得到API签名sign,然后再进行Base64编码。 签名验证算法(接口提供方验证接口请求是否可信,主要算法跟生成API签名的算法是一样的) 主要步骤如下: 1、得到请求方携带的API签名。 2、将所有业务请求参数按字母先后顺序排序。 3、参数名称和参数值链接成一个字符串A。 4、在字符串A的首尾加上apiSecret接口密匙组成一个新字符串B。 5、对新字符串B进行MD5散列运算生成服务器端的API签名,将客户端的API签名进行Base64解码,然后开始验证签名。 6、如果服务器端生成的API签名与客户端请求的API签名是一致的,则请求是可信的,否则就是不可信的。 二分查找和AVL树查找 二分查找要求元素可以随机访问,所以决定了需要把元素存储在连续内存。这样查找确实很快,但是插入和删除元素的时候,为了保证元素的有序性,就需要大量的移动元素了。 如果需要的是一个能够进行二分查找,又能快速添加和删除元素的数据结构,首先就是二叉查找树,二叉查找树在最坏情况下可能变成一个链表。 于是,就出现了平衡二叉树,根据平衡算法的不同有AVL树,B-Tree,B+Tree,红黑树等,但是AVL树实现起来比较复杂,平衡操作较难理解,这时候就可以用SkipList跳跃表结构。 skiplist 跳跃表其实也是一种通过“空间来换取时间”的一个算法,通过在每个节点中增加了向前的指针,从而提升查找的效率。跳跃表使用概率均衡技术而不是使用强制性均衡技术,因此,对于插入和删除结点比传统上的平衡树算法更为简洁高效。 跳表是一种随机化的数据结构,目前开源软件 Redis 和 LevelDB 都有用到它。 Key-Value数据结构 目前常用的key-value数据结构有三种:Hash表、红黑树、SkipList,它们各自有着不同的优缺点(不考虑删除操作): Hash表:插入、查找最快,为O(1);如使用链表实现则可实现无锁;数据有序化需要显式的排序操作。 红黑树:插入、查找为O(logn),但常数项较小;无锁实现的复杂性很高,一般需要加锁;数据天然有序。 SkipList:插入、查找为O(logn),但常数项比红黑树要大;底层结构为链表,可无锁实现;数据天然有序。 如果要实现一个key-value结构,需求的功能有插入、查找、迭代、修改,那么首先Hash表就不是很适合了,因为迭代的时间复杂度比较高;而红黑树的插入很可能会涉及多个结点的旋转、变色操作,因此需要在外层加锁,这无形中降低了它可能的并发度。而SkipList底层是用链表实现的,可以实现为lock free,同时它还有着不错的性能(单线程下只比红黑树略慢),非常适合用来实现我们需求的那种key-value结构。 redis使用跳表(ziplist)? 首先,跳表是skiplist?不是ziplist。ziplist在redis中是一个非常省内存的链表(代价是性能略低),所以在hash元素的个数很少(比如只有几十个),那么用这个结构来存储则可以在性能损失很小的情况下节约很多内存(redis是内存数据库啊,能省还是要省的)。好这个问题清楚了。 如果单纯比较性能,跳跃表和红黑树可以说相差不大,但是加上并发的环境就不一样了,如果要更新数据,跳跃表需要更新的部分就比较少,锁的东西也就比较少,所以不同线程争锁的代价就相对少了,而红黑树有个平衡的过程,牵涉到大量的节点,争锁的代价也就相对较高了。性能也就不如前者了。