为什么数据库需要锁?
数据库是一个多用户使用的共享资源,当多个用户并发的存取数据时吧,在数据库中会产生多个事务同时的存取同一数据库的情况,若对并发操作不加以控制,就可能会读取和存储不正确的数据,破坏数据库的一致性。
数据库中锁的分类有哪些?
按锁的粒度划分:表级锁、行级锁、页级锁
按锁级别划分:共享锁、排它锁、意向锁
共享(读)锁、排他(写)锁、意向共享(读)锁、意向排他(写)锁;
按面向编程的思想划分:乐观锁、悲观锁
注意:看到这些锁不要脑袋发懵,我的理解是,这些锁底层可以说都是通过面向编程的锁演化来的
一般写锁都是一种悲观锁,写的时候阻塞其他人的任何操作,而表级锁/行级锁/页面锁可以使用读锁或者写锁来实现
分别介绍一下不同类型锁的作用?
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁,传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁,写锁等,都是在做操作之前先上锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
表级锁:引擎 MyISAM,直接锁定整张表,如果是表共享读锁(Table Read Lock),则其他线程可以对表进行读操作(它不会阻塞其他用户对同一表的读请求,但会阻塞 对同一表的写操作),如果是表独占写锁(Table Write Lock),其它进程既不能对表进行读操作也无法对表进行写操作(它会阻塞其他线程对同一表的读和写请求)。
MyISAM存储引擎支持:表共享的读锁和表独占的写锁。
MyISAM在执行查询语句(Select)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户控制,是MySQL SERVER端自动完成的。
页级锁:引擎 BDB,表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录
行级锁:引擎 INNODB, 仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作,InnoDB也支持两种形式的行级锁,一种是共享行级锁(读锁),一种是排他行级锁(写锁)。
InnoDB行锁是通过给索引上的索引项加锁来实现的,而不是给表的行记录加锁实现的,这就意味着,只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁(因为没有索引嘛,存储引擎只能给所有的行都加锁,和表锁一样,把记录返回给MySQL Server,它会筛选出符合条件的行进行加锁,其余的行就会释放锁)!
上述三种锁的特性可大致归纳如下:
1) 表级锁:开销小,加锁快;不会出现死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低。
2) 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
3) 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
三种锁各有各的特点,若仅从锁的角度来说,表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如WEB应用,行级锁更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统。
MySQL不同引擎支持的锁的区别?
我们可以使用这个命令查看mysql支持的存储引擎:
SHOW ENGINES;
最常用的两种存储引擎为:InnoDB和MyISAM,下面就使用表格的方式看看这个常用存储引擎的区别:
对比项 InnoDB MyISAM
主外键 支持 不支持
事务 支持 不支持
行表页锁 行锁:操作时只锁某一行,不对其它行有影响,适合高并发操作 表锁:即时操作一条记录也会锁住整张表,不适合高并发操作
缓存 不仅缓存索引,还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性的影响 只缓存索引,不缓存真实数据
表空间 大 小
关注点 事务 性能
默认安装 是 是