锁模块之MyISAM与InnoDB关于锁方面的区别

锁模块

常见问题

  1. MyISAM与InnoDB关于锁方面的区别是什么
  2. 数据库事物的四大特性
  3. 事物隔离级别以及各级别下的并发问题

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

  • MyISAM默认用的是表级锁,不支持行级锁
  • InnoDB默认用的是行级锁,也支持表级锁
  • InnoDB不支持FULLTEXT类型的索引
  • InnoDB中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。
  • 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
  • DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
  • LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

MyISAM引擎

创建表

  CREATE TABLE `person_info_myisam`(

  `id` int(7) NOT NULL AUTO_INCREMENT,

  `account` varchar(10) DEFAULT NULL,

  `name` varchar(20) DEFAULT NULL,

  `area` varchar(20) DEFAULT NULL,

  `title` varchar(20) DEFAULT NULL,

  `motto` varchar(50) DEFAULT NULL,

  PRIMARY KEY `id` ,

  UNIQUE KEY `account` (`account`),

  KEY `index_area_title` (`area`,`title`)

  )  ENGINE=MYISAM DEFAULT CHARSET=utf8;

由于MYISAM不支持事物,所以模仿并发时,需要将表的数据量增加到两千万数据量来真实模拟并发访问的场景,这样MyISAM会给我们加上表级锁。

  • 读锁与写锁互斥:打开一个session对表进行查询"select * from person_info_myisam where id between 1 and 20000000;",由于对表进行查询是会对表加上一个表级的读锁。在查询未结束时,再打开一个session对表进行更新操作"update person_info_myisam set account=account where id=20000001",由于第一个session还未结束,读锁还未释放,这时第二个session加入表级别写锁就会被阻塞,直到读锁释放锁。
  • 读锁是共享锁:打开一个session对表进行查询"select * from person_info_myisam where id between 1 and 20000000;",在查询未结束时,也就是当前session未释放读锁时,再打开一个session对表进行查询"select * from person_info_myisam where id =20000001 ;",此时第二个session并不会被阻塞。
  • 写锁是排他锁:当第一个session对表加上写锁的时候,第二个session无论是对表进行读还是写,都必须等第一个session写锁释放。
  • 如何对读锁加上排他锁:在查询语句后加上 for update,例如"select * from person_info_myisam where id between 1 and 20000000 for update;"

InnoDB引擎

创建表

  CREATE TABLE `person_info_Innodb`(

  `id` int(7) NOT NULL AUTO_INCREMENT,

  `account` varchar(10) DEFAULT NULL,

  `name` varchar(20) DEFAULT NULL,

  `area` varchar(20) DEFAULT NULL,

  `title` varchar(20) DEFAULT NULL,

  `motto` varchar(50) DEFAULT NULL,

  PRIMARY KEY `id` ,

  UNIQUE KEY `account` (`account`),

  KEY `index_area_title` (`area`,`title`)

  )  ENGINE=InnoDB DEFAULT CHARSET=utf8;

InnoDB是支持事物的,但是mysql当中事物是默认提交的,首先要关闭事物自动提交,使用"show variables like 'autocommit';"查看事物提交状态,使用"set autocommit=0;"关闭自动提交

  • 读锁与写锁互斥:打开一个session对行进行查询"select * from person_info_Innodb where id = 3 lock in share mode",由于InnoDB对select语句进行了优化,所以必须要加上 lock in share mode才可以对select进行加读锁,此时再打开一个session对该行进行更新"update person_info_Innodb set title='test3' where id=3;",此时这行就会被锁住,需要第一个session进行commit提交之后,才可以执行更新。如果此时第二个session并不是对id=3的行进行更新而是对其他行进行更新,则不会被锁住,由此证明InnoDB默认支持行级锁
  • 读锁共享锁:打开一个session对行进行查询"select * from person_info_Innodb where id = 3 lock in share mode",再打开一个session对id=3的行进行加读锁"select * from person_info_Innodb where id = 3 lock in share mode",第二个session并不会阻塞。

以上操作都使用了id主键索引走的是行级锁以及gap锁,当不使用索引时,InnoDB走的是表级锁。那么是不是行级锁一定比表级锁要好?那倒未必,锁的粒度越细代价就越高,表级锁是在表头进行加锁,行级锁还要扫描到该行进行加锁,这样的代价比较大。

注意:

MyISAM适合的场景:

  • 频繁执行全表count语句
  • 对数据进行增删改的频率不高,查询非常频繁
  • 没有事物

InnoDB适合的场景:

  • 数据增删改查都相当的频繁
  • 可靠性要求比较高,要求支持事物

数据库锁的分类:

  • 按锁的粒度划分,可分为表级锁、行级锁、页级锁
  • 按锁的级别划分,可分为共享锁、排他锁
  • 按加锁的方式划分,可分为自动锁、显示锁
  • 按操作划分,可分为DML锁,DDL锁
  • 按使用方式划分,可分为乐观锁(在数据库表中加一个列记录当前数据的版本)、悲观锁(上述的MyISAM引擎和InnoDB引擎都是悲观锁)

二、数据库事物的四大特性

ACID

  • 原子性(Atomic)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

三、事物隔离级别以及各级别下的并发访问问题

mysql事物隔离级别的查看

select @@tx_isolation;

 

 

事物隔离级别以及设置

 

1)read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决
2)read committed:读取已经提交的数据 :可以解决脏读 ---- oracle默认的
3)repeatable read:重读读取:可以解决脏读 和 不可重复读 ---mysql默认的
4)serializable:串行化:可以解决 脏读 不可重复读 和 虚读---相当于锁表

 

 

 

 

设置

 

set session transaction isolation level 设置事务隔离级别

 

 

事物并发访问引起的问题以及如何避免

  1. 更新丢失——mysql所有事物隔离级别在数据库层面上均可避免
  2. 脏读——READ-COMMITTED事物隔离级别以上可避免
    在数据库隔离级别为read uncommitted 时会产生脏读,脏读会发生在一个事物A读取了被另一个事物B修改,但还未提交的数据,则事物A读取的是无效的数据,这跟不可重复读类似,但是第二个事物不需要提交
    例如:
      peiqi的账号有1000元,事物A往peiqi账户存200元,但未提交,与此同时
      事物B查询peiqi的账户,这时读取到peiqi账户有1200,随后,
      事物A发生异常,而回滚了事物,peiqi的账户又变为1000。这时事物B读取到peiqi的账户为1200即为脏数据,事物B做了一次脏读
  3. 不可重复读——REPEATABLE-READ事物隔离级别以上可避免
    在数据库隔离级别为read committed及以下;这时在一个事物内,多次读取同一数据,在这个事物还没有结束时,另外一个事物也访问该同一数据。那么,在第一个事物中的;两次读取数据之间,恰好这时又存在第二个事物对这个数据进行修改,那么第一个事物两次读取到的数据可能是不一样的,这样就发生了在同一个事物内两次读取到的数据是不一样的,因此称为是不可重复读。
    例如:
      事物A中,读取到peiqi的账户有1000元,操作没有完成,事物还没有提交,与此同时
      事物B在peiqi的账户增加了200元,并提交了事物,随后
      事物A中,再次读取peiqi的账户,此时账户已经变成了1200元,在同一个事物A中的两次读取的结果不一致,导致了不可重复读。
  4. 幻读——SERIALIZABLE事物隔离级别可避免
    幻读是指当事物不是独立执行时发生的一种现象,例如第一个事物对表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事物也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事物的用户发现表中还有没有修改的数据行,就好像发生幻觉一样。
    例如:
      目前工资为1000的员工有10人,事物A读取所有工资为1000的人数为10人。此时,
      事物B插入一条工资也为1000的记录。
      这时,事物A再次读取工资为1000的员工,记录为11人,此时产生了幻读。

提醒:

不可重复读的重点是修改,同样的条件,你读取过的数据,再次读取出来发现值不一样了

幻读的重点是在于新增或者删除,同样的条件,第一次和第二次读取出来的记录数不一样了

posted @ 2019-05-27 11:41  许明初  阅读(824)  评论(1编辑  收藏  举报