在设计数据库表时,通常需要遵循一些规范,也就是范式。范式主要分为第⼀范式、第⼆范式、第三范式、巴斯-科德范式(BCNF)、第四范式和第五范式,范式级别越⾼对数据表的要求越严格。 通常在设计时,只需要满足第三范式就够了。
数据库事务有四个特性,也就是通常说的ACID。
当多个线程同时对数据库进行操作,就难免会遇到并发问题。事务并发问题有三类:脏读、不可重复读和幻读。
针对于事务可能出现的并发问题,Mysql提供了四种事务隔离级别。
Mysql的默认存储引擎在5.5版本后改为了 InnoDB,特点是⽀持ACID事务、⽀持外键、⽀持⾏级锁提⾼了并发效率。通过锁对象来实现事务相关控制,锁对象可以是表、⻚、⾏等不同粒度的对象。在进⾏锁操作时,InnoDB会根据事务的要求,动态地将锁的粒度从低到⾼升级,在保证数据⼀致性的情况下尽可能地提⾼并发性。
按照锁粒度来分,Mysql锁可分为表级锁、页级锁和行级锁。
表级锁锁住的是整个表,特点是开销⼩,加锁快,锁定⼒度⼤,发⽣锁冲突的概率最⾼,并发度最低,通常⽤于对表进⾏DDL操作或备份等需要操作整张表的情况。
页级锁锁住的是某⼀⻚的数据(16kb左右),特点是开销和加锁时间介于表级和⾏级之间,会出现死锁,锁定⼒度介于表锁和⾏锁之间,并发度⼀般。
行级锁锁住的⾏的数据,特点是锁的实现更加复杂,开销⼤,加锁速度慢。
行级锁可细分为共享锁、排他锁、意向锁。
共享锁⼜称S锁、读锁,可以允许读,但不能写。共享锁可以与共享锁⼀起使⽤。
⽤法:select ... from table_name lock in share mode;
排他锁⼜称X锁、写锁,不能允许读,也不能允许写,排他锁不能与其他锁⼀起使⽤。在mysql中,update,delete,insert,alter 这些写的操作默认都会加上排他锁。select 默认不会加任何锁类型。⼀旦写数据的任务没有完成,数据是不能被其他任务读取的,这对并发操作有较⼤的影响。共享/排他锁的释放⽅式为 commit 或 rollback 。
⽤法:select ... from table_name for update。
innoDB 为了⽀持多粒度的锁,即允许⾏级锁和表级锁共存,⽽引⼊意向锁。意向锁是指未来的某个时刻,事务可能要加共享/排他锁,先提前声明⼀个意向。这样如果有⼈尝试对全表进⾏修改,就不需要判断表中的数据是否被加锁了,只需要通过等待意向互斥锁被释放就⾏了。 意向锁又分为意向共享锁和意向互斥锁。
IX,IS是表级锁,不会和⾏级的X、S锁发⽣冲突,只会和表级的X、S发⽣冲突。意向锁之间是互相兼容的。
记录锁/行锁是指单个⾏记录上的锁。记录锁总是会锁住索引记录,如果 innoDB 存储引擎表在建⽴的时候没有设置任何⼀个索引,那么innoDB存储引擎会使⽤隐式的主键来进⾏锁定。
间隙锁锁住记录中的间隔,即范围查询的记录。间隙锁的主要⽬的就是为了防⽌其他事务在间隔中插⼊数据,以导致不可重复读。如果把事务的隔离级别降级为读已提交(Read Committed),那么间隙锁会⾃动失效。
innoDB默认的隔离级别是可重复读,并且会以临键锁的⽅式对数据⾏进⾏加锁。临键锁是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会⾸先对索引记录加上⾏锁,再对索引记录两边的间隙加上间隙锁。加上间隙锁之后,其他事务就不能在这个间隙修改或者插⼊记录。当查询的索引含有唯⼀属性(唯⼀索引或主键索引)时,Innodb 存储引擎会对临键锁进⾏优化,将其降为行锁,即仅锁住索引本身,⽽不是范围。
插⼊意向锁是⼀种间隙锁形式的意向锁,在真正执⾏ INSERT 操作之前设置。
当执⾏插⼊操作时,总会检查当前插⼊操作的下⼀条记录(已存在的主索引节点)上是否存在锁对象,判断是否锁住了 gap,如果锁住了,则判定和插⼊意向锁冲突,当前插⼊操作就需要等待,也就是配合上⾯的间隙锁或者临键锁⼀起防⽌了幻读操作。
申请插入意向锁的动作是数据库完成的,就是说,事务A申请⼀⾏的⾏锁的时候,数据库会⾃动先开始申请表的插入意向锁。
有了锁,就肯定会出现锁竞争,也就会有锁冲突情况。Mysql中的锁冲突情况主要有下面2种情况:
当出现锁冲突时,事务就需要等待锁资源。如果出现互相等待的情况,那么就会出现死锁问题。下面具体分析下死锁出现的情况。
想象这种情况:事务1持有资源1的锁,事务2持有资源2的锁,事务1申请资源2的锁发⽣等待,这时如果事务2申请资源1的锁,就会出现死锁。这种情况下就需要对某一个事务进行回滚,比如事务2释放资源2的锁,取消对资源1锁的竞争。
假设现在有表 t,只存在 id 为 1和2的记录,当两个事务同时插入不同记录时,场景如下:
注意当对未存在的⾏进⾏加锁的时候,mysql是会锁住⼀段范围,即间隙锁。
假设现在有表 t,主键id最大值是5,模拟场景如下:
要避免死锁,最直接的⽅法就是破坏产⽣死锁的条件,如互斥条件、循环等待等。⽐如:
当出现死锁后,Mysql提供了以下方案来解决:
Mysql中的索引可以分为以下几种:
索引主要有以下四种实现方式:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。