常见知识整理-mysql 锁,隔离级别

MyISAM与InnoDB关于锁方面的区别是什么

  1. MyISAM使用的是表级锁,不支持行级锁
  2. InnoDB支持行级锁,也支持表级锁
  • 因为表级锁是锁住整张表,所以索引和锁没有关系。

  • 但如果是InnoDB,InnoDB中的行级锁是基于索引实现,而不是数据行。所以只有SQL涉及到索引时,才会使用行级锁,否则是表级锁(读锁或写锁)。

  • MyISAM,InnoDB中默认读锁都是共享锁,写锁是排它锁(独占锁)。

对于MyISAM
  1. 当数据被select时,会自动添加上共享读锁,此时其它连接对表做更新时(insertupdatedelete),需要被阻塞等待,但是可以进行读。
  2. 当数据被更新时,会自动添加上排它写锁,此时其它连接对表的curd操作都需要阻塞等待.

手动添加表锁(读锁/写锁)

lock tables person_info_myisam read | write;

手动释放表锁

unlock tables;

查询表级锁争用情况
如果Table_locks_waited比较高,那么说明存在严重的表级锁争用情况

 SHOW STATUS LIKE'table%';

将共享的读锁,变成独占锁

select * from userinfo where id = 123 for update
对于InnoDB

InnoDB用的是二段锁: 即加锁和解锁分成两个步骤,先对同一个事务里的一批操作分别加锁,commit时在对事务里加上的锁进行统一的解锁。

关闭InnoDB事务自动提交
该设置仅针对当前连接生效

SHOW VARIABLES LIKE 'autocommit'  #查看事务开启状态
SET autocommit = 0;               #关闭事务自动提交

InnoDB添加 读 共享锁
select操作默认没有加锁,添加读锁之后,如果没有COMMIT;则,其它连接对同一行无法创建独占锁(例如update,delete操作),

InnoDB中该语句并没有上锁,此时其它连接可以对user_id =12的数据执行更新操作。(注:非阻塞select)
user_id 是索引

SELECT * FROM order_info WHERE user_id = 12

如下语句用于显式添加 共享读锁,其它连接无法对user_id =12的数据执行更新操作(无法创建排它锁),但是可以对user_id不为12的数据做更新操作.

SELECT * FROM order_info WHERE user_id = 12 LOCK IN SHARE MODE;

原因: user_id 是索引,此时使用的是行级锁. 索引值不同,互不影响。

查询行级锁争用情况查询

show status like 'innodb_row_lock%';

关于InnoDB锁总结

  1. 在不通过索引条件查询的时候,InnoDB使用的是表锁,而不是行锁。
  2. 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。
  3. 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
  4. 即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
数据库锁的分类
  • 按锁的粒度划分:表级锁,行级锁,页级锁(bdb引擎支持)
  • 按锁的级别划分:共享锁,排它锁
  • 按锁的方式划分:自动锁,显示锁
  • 按操作划分:分为DML(数据查询语言)锁,DDL(数据定义语言)锁
  • 按使用方式划分:分为乐观锁(代码实现version字段),悲观锁(数据库锁机制实现)
MyISAM适合的场景
  1. 频繁执行全表count语句(MyISAM内部通过一个变量保存总数,而InnoDB每次都需要扫表统计)
  2. 对数据进行增、删、改的频率不高,查询非常频繁
  3. 没有事务
InnoDB适合的场景
  1. 数据CRUD都相当频繁
  2. 可靠性要求比较高,要求支持事务

数据库事务的四大特性

ACID
原子性(Atomic):事务包含的所有操作,要么全执行,要么全不执行。
一致性(Consistency):事务一致性
隔离性(Isolation)
持久性(Durability):数据库持久化

事务隔离级别以及各级别下的并发访问问题

隔离级别从低到高如下:

  1. read uncommitted(未提交读)
  2. read committed(提交读)
  3. repeatable read(重复读)
  4. serializable(串行读)

查看mysql事务隔离级别:

SELECT @@transaction_isolation  #默认 REPEATABLE-READ

修改事务隔离级别
这里修改为: read uncommitted

set session transaction isolation level read uncommitted
  • 更新丢失: 即一个事务的更新,覆盖了另一个事务的更新。
    mysql所有事务隔离级别在数据库层面上均可避免

  • 脏读:read uncommitted级别下,A更新数据1,但未提交,此时B读取了A未提交事务的数据,但可能A回滚事务数据实际并未更新,导致B读取了脏数据,出现了脏读。
    Read-Committed 事务隔离级别以上可避免

  • 不可重复读: 即同一个事务中两次读取的通过一条数据结果不一样,
    Repeatable-read 事务隔离级别以上可避免

  • 幻读: A查询出3条数据,更新时却更新了4条,可能B在这期间新增了一条。serializable事务隔离级别可避免,所有的sql都会加锁。

事务隔离级别更新丢失脏读不可重复读幻读
read uncommitted避免发生发生发生
read committed避免避免发生发生
repeatable read避免避免避免发生
serializable避免避免避免避免

InnoDB可重复读(RR)隔离级别下如何避免幻读

当前读select...lock in share modeselect...for updateupdatedeleteinsert
就是读取或更新的都是最新的数据
快照读:不加锁的非阻塞读,默认select ,(非serializable隔离级别下,serializable隔离级别本身就是串行,该模式下快照读退化成当前读),快照读的实现是基于多版本并发控制即MVCC,MVCC可以认为是行级锁的变种,性能高于行级锁,但读取的可能并不是数据的最新版本。

RC RR级别下的InnoDB的非阻塞读如何实现

next-key锁
Gap锁会用在非唯一索引或者不走索引的当前读中

语法

Group By
  1. 满足select子句中的列名必须为分组列或者列函数
  2. 列函数对于group by子句定义的每个组各返回一个结果
Having
  1. 通过与group by子句一起使用
  2. where过滤行,having过滤组
  3. 出现在同一行sql的顺序:where > group by > having
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值