MySQL 索引
- IO
- B+树
IO
数据库的索引和数据都存储在磁盘中。
B树的一个节点可以存储多个元素,相对于完全平衡二叉树整棵树的高度更低,磁盘IO效率更高。而,B+树是B树的升级版,非叶子节点只存储key,不存储数据,同样大小的磁盘页可以容纳更多节点,所以IO次数更少。
局部性原理:当一个数据被用到时,其附近的数据也通常会马上被使用。
磁盘预读:所以操作系统为了提高效率,读取数据时往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,操作系统也会从这个位置开始,顺序向后读取一定长度的数据放入内存。这里的一定长度叫做页,也就是操作系统操作磁盘时的基本单位。一般操作系统中一页的大小是4Kb。
参考链接:https://blog.csdn.net/weixin_39812224/article/details/113284079
B+树
b+树图文详解_lzf的博客-CSDN博客
Mysql索引结构用B+树-好在哪?
B树和B+树的区别:
- B树的非叶子节点和叶子节点都存储key和数据, B+树的非叶子节点只存储key,叶子节点存储key和数据;
- B+树的叶子节点之间通过双向链表有序链接。
- B树中一条记录只会出现一次,不会重复出现,而B+树的键则可能重复重现,这么做的好处是为了提高范围查找的效率。
B+树的优点:
- 非叶子节点只存储key,不存储数据,同样大小的磁盘页可以容纳更多节点,所以IO次数更少;
- 叶子节点形成有序链表,便于范围查询。
B+树中一个节点到底存多少个元素合适?
其实也可以换个角度来思考B+树中一个节点到底多大合适?答案是:B+树中一个节点为一页或页的倍数最为合适。因为如果一个节点的大小小于1页,那么读取这个节点的时候其实也会读出1页,造成资源的浪费;如果一个节点的大小大于1页,比如1.2页,那么读取这个节点的时候会读出2页,也会造成资源的浪费;所以为了不造成浪费,所以最后把一个节点的大小控制在1页、2页、3页、4页等倍数页大小最为合适。
那么,Mysql中B+树的一个节点大小为多大呢?
这个问题的答案是“1页”,这里说的“页”是Mysql自定义的单位(其实和操作系统类似),Mysql的Innodb引擎中一页的默认大小是16k(如果操作系统中一页大小是4k,那么Mysql中1页=操作系统中4页),可以使用命令SHOW GLOBAL STATUS like 'Innodb_page_size';查看。并且还可以告诉你的是,一个节点为1页就够了。
为什么不用hash索引
MEMORY引擎支持hash索引,么InnoDB和MyISAM引擎不支持HASH索引。
- HASH索引本身只存储对应的HASH值和行指针,而不是存储字段值
- HASH索引并不是按照索引顺序来存储的,因此无法排序
- HASH索引不支持部分索引列查找,因为HASH索引是使用全部的内容来计算HASH值的。如在(A,B)两列建立索引,只查询A无法使用索引
- HASH索引只支持等值比较查询,包括 =、IN()不能进行任何的范围查询
- 最严重的是既然HASH值是数字,肯定会出现相同的,也就是HASH冲突
- 出现HASH冲突的时候,存储引擎必须遍历链表中所有的行指针,逐行进行比较,直到找到所有符合条件的行
- 当HASH冲突特别多的时候,维护操作的成本就会变大,比如一次数据的删除引擎需要遍历对应HASH值链表上的每一行,找到并删除对应的引用,冲突越多,代价越大
参考链接:https://blog.csdn.net/qq_39455116/article/details/86496053
常见的数据库优化手段
- 数据库设计:数据表设计遵循三范式,使用合适的数据类型,使用合适的存储引擎
第一范式1NF:字段原子性;
第二范式2NF: 消除部分依赖;
第三范式3NF:在2NF的基础上添加外键。 - 适当创建索引
- 数据库扩展:数据库的分表分库,读写分离等
- SQL语句优化等
(1) 查询尽量避免全表扫描,首先考虑在where、order by字段上添加索引
(2) 避免在where字段上使用NULL值,所以在设计表时尽量使用NOT NULL约束,有些数据会默认为NULL,可以设置默认值为0或者-1
(3) 避免在where子句中使用!=或<>操作符,Mysql只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE使用索引
(4) 避免在where中使用OR来连接条件,否则可能导致引擎放弃索引来执行全表扫描,可以使用UNION进行合并查询:
select id from t where num = 30 union select id from t where num = 40;
(5) 尽量避免在where子句中进行函数或者表达式操作
(6) 最好不要使用select * from t,用具体的字段列表代替"*",不要返回用不到的任何字段
(7) in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num IN(1,2,3)如果是连续的值建议使用between and,select id from t where between 1 and 3;
(8) select id from t where col like %a%;模糊查询左侧有%会导致全表检索,如果需要全文检索可以使用全文搜索引擎比如es,slor
(9) limit offset rows关于分页查询,尽量保证不要出现大的offset,比如limit 10000,10相当于对已查询出来的行数弃掉前10000行后再取10行,完全可以加一些条件过滤一下(完成筛选),而不应该使用limit跳过已查询到的数据。这是一个==offset做无用功==的问题。对应实际工程中,要避免出现大页码的情况,尽量引导用户做条件过滤。
链接:
面试不再尬聊的Mysql数据库优化方案_路漫漫其修远兮,吾将上下而求索-CSDN博客_mysql数据库优化面试
索引的优缺点,什么字段上建立索引

索引的优点:
① 建立索引的列可以保证行的唯一性,生成唯一的rowId
② 建立索引可以有效缩短数据的检索时间
③ 建立索引可以加快表与表之间的连接
④ 为用来排序或者是分组的字段添加索引可以加快分组和排序顺序
索引的缺点:
① 创建索引和维护索引需要时间成本,这个成本随着数据量的增加而加大
② 创建索引和维护索引需要空间成本,每一条索引都要占据数据库的物理存储空间,数据量越大,占用空间也越大(数据表占据的是数据库的数据空间)
③ 会降低表的增删改的效率,因为每次增删改索引需要进行动态维护,导致时间变长
聚簇索引和非聚簇索引
聚簇索引
聚簇索引一般是主键索引。如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。
聚簇索引的叶子节点中存放聚簇索引对应的数据行。因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引(不过,覆盖索引可以模拟多个聚簇索引的情况)。
二级索引(即除了聚簇索引以外的索引)的叶子节点保存行的主键值,因此二级索引访问数据行需要两次索引查找(二级索引->聚簇索引->数据行)。
InnoDB 是聚簇索引。

非聚簇索引
表数据存储顺序与索引顺序无关,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。
MyISAM 是非聚簇索引。
索引失效的情况

MyISAM 和 InnoDB

是否⽀持⾏级锁 : MyISAM 只有表级锁(table-level locking),⽽InnoDB ⽀持⾏级锁(rowlevel locking)和表级锁,默认为⾏级锁。
是否⽀持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原⼦性,其执⾏速度⽐InnoDB类型更快,但是不提供事务⽀持。但是InnoDB 提供事务⽀持事务,外部键等⾼级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能⼒(crash recoverycapabilities)的事务安全(transaction-safe (ACID compliant))型表。
是否⽀持MVCC :仅 InnoDB ⽀持。应对⾼并发事务, MVCC⽐单纯的加锁更⾼效;MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下⼯作;MVCC可以使⽤ 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统⼀。
是否⽀持外键: MyISAM不⽀持,⽽InnoDB⽀持。
都用B+树,但是MyISAM不是聚簇索引,⽽InnoDB是聚簇索引。
一条SQL语句在MySQL中是如何执行的

查询语句
权限校验---》(如果命中缓存)查询缓存---》分析器---》优化器---》权限校验---》执行器---》引擎
- 连接器:权限校验
- 查询缓存:mysql8.0 之前会查询缓存,如果有符合的返回缓存
- 分析器
- 词法分析:提取关键词,比如提取上面这个语句是查询select,提取需要查询的表名为tb_student,需要查询所有的列,查询条件是这个表的id='1'。
- 语法分析:sql语句是否有语法错误
- 优化器:确定执行方案
- 权限校验
- 执行器:返回接口执行的结果。
更新语句

为什么redo log 要引入prepare预提交状态?
先写redo log 直接提交,然后写 binlog,假设写完redo log 后,机器挂了,binlog日志没有被写入,那么机器重启后,这台机器会通过redo log恢复数据,但是这个时候bingog并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
先写binlog,然后写redo log,假设写完了binlog,机器异常重启了,由于没有redo log,本机是无法恢复这一条记录的,但是binlog又有记录,那么和上面同样的道理,就会产生数据不一致的情况。
如果采用redo log 两阶段提交的方式就不一样了,写完binglog后,然后再提交redo log就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设redo log 处于预提交状态,binglog也已经写完了,这个时候发生了异常重启会怎么样呢?
这个就要依赖于mysql的处理机制了,mysql的处理过程如下:
判断redo log 是否完整,如果判断是完整的,就立即提交。
如果redo log 只是预提交但不是commit状态,这个时候就会去判断binlog是否完整,如果完整就提交 redo log, 不完整就回滚事务。
这样就解决了数据一致性的问题。
步骤
分析器----》权限校验----》执行器---》引擎---redo log(prepare 状态---》binlog---》redo log(commit状态)
- 先查询到张三这一条数据,如果有缓存,也是会用到缓存。
- 然后拿到查询的语句,把 age 改为19,然后调用引擎API接口,写入这一行数据,InnoDB引擎把数据保存在内存中,同时记录redo log,此时redo log进入prepare状态,然后告诉执行器,执行完成了,随时可以提交。
- 执行器收到通知后记录binlog,然后调用引擎接口,提交redo log 为提交状态。
- 更新完成。
参考链接:一条SQL语句在MySQL中是如何执行的
分库分表

主从复制
原理

主从同步延时分析

模式
一主一从
主主复制
一主一从
多主一从
级联复制
事物的四⼤特性 ACID
原⼦性(Atomicity): 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么完全不起作⽤;
⼀致性(Consistency): 执⾏事务前后,数据保持⼀致,多个事务对同⼀个数据读取的结果是相同的;
隔离性(Isolation): 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间是独⽴的;
持久性(Durability): ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。
一致性
ACID里的AID都是数据库的特征,也就是依赖数据库的具体实现。而唯独这个C,实际上它依赖于应用层,也就是依赖于开发者。这里的一致性是指系统从一个正确的状态,迁移到另一个正确的状态。什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态。而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性。
所以,你可以理解一致性就是:应用系统从一个正确的状态到另一个正确的状态。而ACID就是说事务能够通过AID来保证这个C的过程。C是目的,AID都是手段。
mysql中的原子性和持久性是如何保证的?
原子性通过undo log来实现;
持久性通过redo log来实现。
binlog,undo log 和 redo log
binlog
MySQL 自带的日志模块式binlog(归档日志),所有的存储引擎都可以使用。
MySQL 的二进制日志 binlog 可以说是 MySQL 最重要的日志,它记录了所有的 DDL 和 DML 语句(除了数据查询语句select、show等),以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二进制日志是事务安全型的。binlog 的主要目的是复制和恢复。
Binlog日志的两个最重要的使用场景
- MySQL主从复制:MySQL Replication在Master端开启binlog,Master把它的二进制日志传递给slaves来达到master-slave数据一致的目的
- 数据恢复:通过使用 mysqlbinlog工具来使恢复数据
undo log
undo log是把所有没有COMMIT的事务回滚到事务开始前的状态,系统崩溃时,可能有些事务还没有COMMIT,在系统恢复时,这些没有COMMIT的事务就需要借助undo log来进行回滚。
redo log
InnoDB引擎还自带了一个日志模块redo log。
MyISAM引擎是没有redo log的,不支持事务的。
所以并不是说只用一个日志模块不可以,只是InnoDB引擎就是通过redo log来支持事务的。
redo log是指在回放日志的时候把已经COMMIT的事务重做一遍,对于没有commit的事务按照abort处理,不进行任何操作。
参考链接:
并发造成的问题
脏读(Dirty read): 当⼀个事务正在访问数据并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时另外⼀个事务也访问了这个数据,然后使⽤了这个数据。因为这个数据是还没有提交的数据,那么另外⼀个事务读到的这个数据是“脏数据”,依“脏数据”所做的操作可能是不正确的。
丢失修改(Lost to modify): 指在⼀个事务读取⼀个数据时,另外⼀个事务也访问了该数据,那么在第⼀个事务中修改了这个数据后,第⼆个事务也修改了这个数据。这样第⼀个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
不可重复读(Unrepeatableread): 指在⼀个事务内多次读同⼀数据。在这个事务还没有结束时,另⼀个事务也访问该数据。那么,在第⼀个事务中的两次读数据之间,由于第⼆个事务的修改导致第⼀个事务两次读取的数据可能不太⼀样。这就发⽣了在⼀个事务内两次读到的数据是不⼀样的情况,因此称为不可重复读。
幻读(Phantom read): 幻读与不可重复读类似。它发⽣在⼀个事务(T1)读取了⼏⾏数据,接着另⼀个并发事务(T2)插⼊或删除了⼀些数据时。在随后的查询中,第⼀个事务(T1)就会发现多了⼀些原本不存在的记录,或者少了一些记录,就好像发⽣了幻觉⼀样,所以称为幻读。
SQL事务隔离级别
READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣。
REPEATABLE-READ(可重复读): 对同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。
SERIALIZABLE(可串⾏化): 最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防⽌脏读、不可重复读以及幻读。

MySQL InnoDB 存储引擎的默认的隔离级别是 REPEATABLE-READ(可重读)。
与 SQL 标准不同的地⽅在于 InnoDB 存储引擎在 REPEATABLEREAD(可重读)事务隔离级别下使⽤的是Next-Key Lock 锁算法,因此可以避免幻读的产⽣,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重读)已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串⾏化) 隔离级别。因为隔离级别越低,事务请求的锁越少,所以⼤部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是你要知道的是InnoDB 存储引擎默认使⽤ REPEATABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下⼀般会⽤到 SERIALIZABLE(可串⾏化) 隔离级别。
MVCC 多版本并发控制









MVCC
就是多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。
为什么需要MVCC呢?数据库通常使用锁来实现隔离性。最原生的锁,锁住一个资源后会禁止其他任何线程访问同一个资源。但是很多应用的一个特点都是读多写少的场景,很多数据的读取次数远大于修改的次数,而读取数据间互相排斥显得不是很必要。所以就使用了一种读写锁的方法,读锁和读锁之间不互斥,而写锁和写锁、读锁都互斥。这样就很大提升了系统的并发能力。之后人们发现并发读还是不够,又提出了能不能让读写之间也不冲突的方法,就是读取数据时通过一种类似快照的方式将数据保存下来,这样读锁就和写锁不冲突了,不同的事务session会看到自己特定版本的数据。当然快照是一种概念模型,不同的数据库可能用不同的方式来实现这种功能。
InnoDB与MVCC
MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作。其他两个隔离级别够和MVCC不兼容, 因为 READ UNCOMMITTED 总是读取最新的数据行, 而不是符合当前事务版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁。
Redo log, bin log, Undo log
InnoDB中通过undo log实现了数据的多版本,而并发控制通过锁来实现。
undo log除了实现MVCC外,还用于事务的回滚。MySQL Innodb中存在多种日志,除了错误日志、查询日志外,还有很多和数据持久性、一致性有关的日志。
binlog,是mysql服务层产生的日志,常用来进行数据恢复、数据库复制,常见的mysql主从架构,就是采用slave同步master的binlog实现的, 另外通过解析binlog能够实现mysql到其他数据源(如ElasticSearch)的数据复制。
redo log记录了数据操作在物理层面的修改,mysql中使用了大量缓存,缓存存在于内存中,修改操作时会直接修改内存,而不是立刻修改磁盘,当内存和磁盘的数据不一致时,称内存中的数据为脏页(dirty page)。为了保证数据的安全性,事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中, redo log是按照顺序写入的,磁盘的顺序读写的速度远大于随机读写。当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。这样实现了事务的原子性、一致性和持久性。
undo log: 除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC。
版本链与Undo log
innodb中通过B+树作为索引的数据结构,并且主键所在的索引为ClusterIndex(聚簇索引), ClusterIndex中的叶子节点中保存了对应的数据内容。一个表只能有一个主键,所以只能有一个聚簇索引,如果表没有定义主键,则选择第一个非NULL唯一索引作为聚簇索引,如果还没有则生成一个隐藏id列作为聚簇索引。
除了Cluster Index外的索引是Secondary Index(辅助索引)。辅助索引中的叶子节点保存的是聚簇索引的叶子节点的值。
InnoDB行记录中除了刚才提到的rowid外,还有trx_id和db_roll_ptr, trx_id表示最近修改的事务的id,db_roll_ptr指向undo segment中的undo log。
新增一个事务时事务id会增加,trx_id能够表示事务开始的先后顺序。
Undo log分为Insert和Update两种,delete可以看做是一种特殊的update,即在记录上修改删除标记。
update undo log记录了数据之前的数据信息,通过这些信息可以还原到之前版本的状态。
当进行插入操作时,生成的Insert undo log在事务提交后即可删除,因为其他事务不需要这个undo log。
进行删除修改操作时,会生成对应的undo log,并将当前数据记录中的db_roll_ptr指向新的undo log。

ReadView
ReadView 有四个关键属性:
- m_ids:在生成 ReadView 时当前系统中活跃的事务的事务ID列表。
- min_trx_id:生成 ReadView 时当前系统中活跃的事务中最小的事务ID,也就是m_ids中的最小值。
- max_trx_id:生成 ReadView 时系统中分配给下一个事务的ID值,就是全局事务ID(Max Trx Id),注意并不是m_ids中的最大值。
- creator_trx_id:生成该 ReadView 的事务的事务ID。事务中只有在执行了增删改操作时才会分配一个事务ID,如果是一个只读事务,那 creator_trx_id 默认就为0。
有了ReadView后,在事务中查询的时候,就可以沿着 undo 版本链查找当前事务可见的版本。这时 undo log 中的隐藏列 trx_id 就派上用场了,它表示产生这条 undo log 时的事务的事务ID。判断此版本是否可访问的依据就是用 undo log 中的 trx_id 属性值与 ReadView 中的各个属性做比较。
通过如下步骤来判断版本是否可被访问:
① 如果 trx_id 等于 creator_trx_id ,说明当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
② 如果 trx_id 小于 min_trx_id,说明生成该版本的事务在当前事务生成 ReadView 前已经提交,所以该版本可以被当前事务访问。
③ 如果 trx_id 大于或等于max_trx_id,说明生成该版本的事务在当前事务生成 ReadView 后才开启,所以该版本不可以被当前事务访问。
④ 如果 trx_id 在 min_trx_id 和 max_trx_id 之间,此时再判断一下 trx_id 是不是在 m_ids 列表中,如果在,说明创建 ReadView 时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

READ COMMITTED 和 REPEATABLE READ 隔离级别的区别就是它们生成ReadView的时机不同。
- READ COMMITTED 是每次查询前都会生成一个独立的 ReadView。
- REPEATABLE READ 则只在第一次查询前生成一个 ReadView,之后的查询都重复使用这个 ReadView。
这就是Mysql的MVCC,通过版本链,实现多版本,可并发读-写,写-读。通过ReadView生成策略的不同实现不同的隔离级别。
参考链接:
https://baijiahao.baidu.com/s?id=1629409989970483292&wfr=spider&for=pc
https://zhuanlan.zhihu.com/p/66791480
https://juejin.cn/post/6978632592140533796
锁
InnoDB存储引擎的锁的算法有三种:
- Record lock:单个⾏记录上的锁
- Gap lock:间隙锁,锁定⼀个范围,不包括记录本身
- Next-key lock:record+gap 锁定⼀个范围,包含记录本身
InnoDB 存储引擎的默认⽀持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过 SELECT @@tx_isolation; 命令来查看。
这⾥需要注意的是:与 SQL 标准不同的地⽅在于, InnoDB 存储引擎在 REPEATABLEREAD(可重读)事务隔离级别下使⽤的是Next-Key Lock 锁算法,因此可以避免幻读的产⽣,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认⽀持的隔离级别 REPEATABLE-READ(可重读)已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串⾏化) 隔离级别。
因为隔离级别越低,事务请求的锁越少,所以⼤部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是你要知道的是InnoDB 存储引擎默认使⽤ REPEATABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下⼀般会⽤到 SERIALIZABLE(可串⾏化) 隔离级别。
相关知识点:
- innodb对于⾏的查询使⽤next-key lock
- Next-locking keying为了解决Phantom Problem幻读问题
- 当查询的索引含有唯⼀属性时,将next-key lock降级为record key
- Gap锁设计的⽬的是为了阻⽌多个事务将记录插⼊到同⼀范围内,⽽这会导致幻读问题的产⽣
- 有两种⽅式显式关闭gap锁:(除了外键约束和唯⼀性检查外,其余情况仅使⽤record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
乐观锁和悲观锁


sql join 原理



防止sql注入的方法
- 前端过滤,输入框中过滤特殊字符,或者限制输入的字符集合
- 代码层手动过滤,同上
- 利用连接池组件过滤,比如druid的WallFilter
- 使用预编译,比如 jdbc 的preparedStatement
- 使用存储过程,只传入参数