之前学习MySql的简单使用的时候.学习了事务的概念,事务的隔离级别,以及何时使用事务,怎么使用事务等等比较简单的东西。最近不停的在想数据库内部是如何实时事务的,如何避免脏数据的。数据库内部是否有与并发编程中的相似的锁概率呢。Google查阅了相关资料后,记录一下学习笔记。
mysql的锁的概述
锁的概率:某个链接对某个资源(可以是一张表,也有可能是一行或者多行记录)进行加锁操作,根据锁的不同功能,决定在加锁期间,其他链接是否允许对该资源有相应的处理权限。
那么mysql究竟有哪几种类锁呢?
一、按操作划分,可分为DML锁、DDL锁
二、按锁的粒度划分,可分为表级锁、行级锁、页级锁(mysql BDB支持)
三、按锁级别划分,可分为共享锁、排他锁
四、按加锁方式划分,可分为自动锁、显示锁
五、按使用方式划分,可分为乐观锁、悲观锁
DML锁(data locks,数据锁),用于保护数据的完整性,其中包括行级锁(Row Locks (TX锁))、表级锁(table lock(TM锁))。 DDL锁(dictionary locks,数据字典锁),用于保护数据库对象的结构,如表、索引等的结构定义。其中包排他DDL锁(Exclusive DDL lock)、共享DDL锁(Share DDL lock)、可中断解析锁(Breakable parse locks)
共享锁
共享锁就是只针对update时候加锁,在未对update操作提交之前,其他事务只能够获取最新的记录但不能够update操作。
举个例子说吧,假如说事务A读到一条记录,并且修改了该条记录的一个字段的值a改成了b,正在这个时候事务B也读到了这条记录并且获取的A事务修改后的字段值b,事务B想把该字段的值改为c,在此时事务A的修改操作并未提交。那对不起了事务B,因为是事务A先对该记录加锁的,你此时还没有对该条记录上锁的权限哦,不要急哦,等事务A提交之后你就可以改了。
排他锁
一开始就对记录上锁了,在本事务未提交之前别的事务无权进行任何操作。
还是用上个例子吧,事务A查到一个记录,并修改了其中的一个字段a的值为b,这个时候事务B来获取这条记录,我靠,怎么获取不到呢?原来是排他锁在作怪,这是什么情况。原来排他锁在获取记录的时候就对这条记录上了锁,而且别的事务连获取这条记录的权限都没有,更别提要修改了,必须等到事务A提交了事务释放了锁之后别的事务才能够获取到这条记录。
这两种锁各有利弊,具体使用要看你项目的具体业务的。
- 假如你的项目对并发很高对效率要求很高,那么你该选用共享锁,因为在别的事务对某些记录上锁后在事务未提交之前其他事务是有权限去查看的,但是当出现意外导致事务回滚时候,其他事务会多进行一步操作,那就是重新获取这些对象了,不过这比排队等锁要好多了。
- 假如你的项目并发数不是很多,同时对整个业务的原子操作要求很高这个时候排他锁是很不错的选择。
mysql的锁的级别的区别
mysql究竟能对那些对象上锁呢?现在学习mysql的锁的级别了。
mysql锁的级别分为三类:页级锁,表级锁,行级锁。
那有三个级别的锁,mysql究竟用的是哪个级别的呢?这个还得看你用的是什么mysql的引擎了
mysql大概有下面几个数据库引擎和对应的锁级别
- MyISAM引擎:使用的是表级锁。理解为锁住整个表,可以同时读,写不行。
- MEMORY/heap:使用的是表级锁。理解为锁住整个表,可以同时读,写不行。
- BDB:使用的是页级锁,它也支持表级锁。一次锁定相邻的一组记录。
- InnoDB:使用的是行级锁,它也支持表级锁。单独的一行记录加锁 。
三种锁的特性可大致归纳如下:
- 1) 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。分为表共享读锁(共享锁)与表独占写锁(排他锁)。
- 2) 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 行级锁分为共享锁 和 排他锁。
- 3) 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
这里我们主要讨论InnoDB存储引擎,也谈论的是行级锁,一般的在秒杀系统中我们会对商品库存使用行级锁,因为秒杀的时候库存是一个很重要的数据,我们在创建数据库的表时可能会出现下面这样的设置:
ENGINE = InnoDB AUTO_INCREMENT=10 DEFAULT CHARACTER SET = utf8 comment='用户表'
将引擎设置为InnoDB,InnnoDB与其他引擎的不同:一是支持事务(TRANCSACTION),二是采用了行级锁。
InnoDB中两种模式的行级锁:(也就是最开始讨论的那种锁)
- 1)共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
( Select * from table_name where ……lock in share mode)- 2)排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和 排他写锁。(select * from table_name where…..for update)
为了允许行锁和表锁共存,实现多粒度锁机制;同时还有两种内部使用的意向锁(都是表锁),分别为意向共享锁和意向排他锁。意向锁是表级锁,其设计目的主要是为了在一个事务中揭示下一行将要被请求锁的类型。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
意向锁是InnoDB自动加的,不需要用户干预。
对于insert、update、delete,InnoDB会自动给涉及的数据加排他锁(X);对于一般的Select语句,InnoDB不会加任何锁,事务可以通过以下语句给显示加共享锁或排他锁。
共享锁:SELECT … LOCK IN SHARE MODE;
排他锁:SELECT … FOR UPDATE;
注意:InnoDB行锁是通过给索