Mysql面试

35 阅读6分钟

1.Mysql有哪几种锁

1.按照对数据操作锁的粒度来分

MyISAM和MEMORY采用表级锁(table-level locking)

BDB采用页面锁(page-level locking)或表级锁,默认为页面锁

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

1.行级锁

描述: 行级锁是Mysql中粒度最细的一种锁。表示只针对当前操作的行进行加锁。减少数据库的锁冲突。并发性能高。但是加锁的开销也最大。行级锁分为共享锁和排他锁

特点:开销大,加锁慢,会出现死锁,发生锁冲突的概率最低,并发度也最高。

其实行级锁和页级锁之间还有其他锁粒度的锁,就是间隙锁和临键锁。

InnoDB有三种行锁的算法:

1,Record Lock(记录锁):单个行记录上的锁。这个也是我们日常认为的行锁。

2,Gap Lock(间隙锁):间隙锁,锁定一个范围,但不包括记录本身(只不过它的锁粒度比记录锁的锁整行更大一些,他是锁住了某个范围内的多个行,包括根本不存在的数据)。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。该锁只会在隔离级别是RR或者以上的级别内存在。间隙锁的目的是为了让其他事务无法在间隙中新增数据。

3,Next-Key Lock(临键锁):它是记录锁和间隙锁的结合,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。next-key锁是InnoDB默认的锁

上面这三种锁都是排它锁(X锁)

2.表级锁

描述:表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分mysql引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)

特点:开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。

  • LOCK TABLE my_table_name READ; 用读锁锁表,会阻塞其他事务修改表数据。
  • LOCK TABLE my_table_name WRITE; 用写锁锁表,会阻塞其他事务读和写。

MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

但是在InnoDB中如果需要表锁就需要显式地声明了。

3.页级锁

描述:页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折中的页级锁,一次锁定相邻的一组记录。BDB 支持页级锁。

特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

2.按照锁的共享策略来分

共享锁和排他锁在MySQL中具体的实现就是读锁和写锁

  1. 读锁(共享锁):Shared Locks(S锁),针对同一份数据,多个读操作可以同时进行而不会互相影响
  2. 写锁(排它锁):Exclusive Locks(X锁),当前写操作没有完成前,它会阻断其他写锁和读锁
  3. IS锁:意向共享锁、Intention Shared Lock。表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁。
  4. IX锁:意向排他锁、Intention Exclusive Lock。表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。

为什么需要意向锁呢? 有这么一个场景,当一个事务想要给一张表加上表锁,其前提是没有其他任何事务已经锁定了这张表的任意一行数据。 也就是说,需要去全表扫描,看是否有哪一行数据被其他事务锁定了,但是这非常低效。 因此引入了意向锁,意向锁相当于一个标识,表示是否有其他事务锁定该表的其他行数据。

3.按照加锁策略上分

1.悲观锁

悲观锁认为对于同一个数据的并发操作,一定是会发生修改的(或者增删改多,查少),哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。

2.乐观锁

乐观锁则认为对于同一个数据的并发操作,是不会发生修改的(或者增删改少,查多)。在更新数据的时候,会采用不断尝试更新的方式来修改数据。也就是先不管资源有没有被别的线程占用,直接取申请操作,如果没有产生冲突,那就操作成功,如果产生冲突,有其他线程已经在使用了,那么就不断地轮询。乐观的认为,不加锁的并发操作是没有事情的。就是通过记录一个数据历史记录的多个版本,如果修改完之后发现有冲突再将版本返回到没修改的样子,乐观锁就是不加锁。好处就是减少上下文切换,坏处是浪费CPU时间。

4.其他:自增锁

自增锁(AUTO-INC锁) 自增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。通过innodb_autoinc_lock_mode参数可以设置自增主键的生成策略。防止并发插入数据的时候自增id出现异常。

当一张表的某个字段是自增列时,innodb会在该索引的末位加一个排它锁。为了访问这个自增的数值,需要加一个表级锁,不过这个表级锁的持续时间只有当前sql,而不是整个事务,即当前sql执行完,该表级锁就释放了。其他session无法在这个表级锁持有时插入任何记录。

2.简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别

MyISAMInnoDB
事务不支持支持
外键不支持支持
聚簇索引不支持支持
表数据行数保存不保存
支持表级锁支持表级锁 行级锁
唯一索引(主键)可以没有必须有

3.MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

脏读不可重复读幻读
read uncommited可能可能可能
read commited可能可能
repeatable read可能
serializable

4.MySQL索引失效的情况

  1. 查询条件中有or,即使有部分条件带索引也会失效
  2. like查询 的%在前面
  3. 如果列类型是字符串,那在查询条件中需要将数据没有用引号引用起来
  4. 索引列上参与计算会导致索引失效(和第三种类似 都是经过函数操作)
  5. 违背最左匹配原则
  6. 如果mysql估计全表扫描要比使用索引要快,会不适用索引