MySQL中的锁:
从锁定粒度上区分为:表级锁,页级锁,行级锁。
- 表级锁:
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度低。
代表引擎是MyISAM引擎。
表级锁定分为:表共享读锁(共享锁)与表独占写锁(排他锁)。
注:
开销小:指加锁资源消耗较少
锁定粒度大:指锁的级别,最小的行级锁,最大的表锁。
锁冲突高:因为针对整个表加锁,除非没有其他人操作否则冲突。 - 页级锁(不详解):
特点:优缺点介于表级锁和行级锁之间,粒度为相邻一组数据行。
代表引擎是BDB引擎。 - 行级锁:
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突概率最低,并发度也最高。
代表引擎是InnoDB引擎。InnoDB也支持表级锁,默认为行级锁
行级锁分为:共享锁和排他锁
注:
死锁:两个进程同时操作一组数据,相互争夺控制权,造成相互等待若无外力不继续进行一直等待的现象,称之为死锁。
当两个事务同时执行,一个锁住了主键索引,在等待其他相关索引。另一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。
行锁与表锁:InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁
从保证数据一致性上区分:共享锁(表-读锁)、排他锁(表-写锁)
- 共享锁(share lock)
共享锁又称读锁,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。MyISAM 存储引擎只支持表锁,MySQL 的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。
对于读操作,可以增加读锁,一旦数据表被加上读锁,其他请求可以对该表再次增加读锁,但是不能增加写锁。(当一个请求在读数据时,其他请求也可以读,但是不能写,因为一旦另外一个线程写了数据,就会导致当前线程读取到的数据不是最新的了。这就是不可重复读现象)
对表test_table增加读锁:
LOCK TABLES test_table READ
UNLOCK test_table - 排他锁(exclusive Lock)
排他锁又称写锁,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
对于写操作,可以增加写锁,一旦数据表被加上写锁,其他请求无法在对该表增加读锁和写锁。(当一个请求在写数据时,其他请求不能执行任何操作,因为在当前事务提交之前,其他的请求无法看到本次修改的内容。这有可能产生脏读、不可重复读和幻读)
读锁和写锁都是阻塞锁。读写同时默认写优先,即使后进也优先(默认)
对表test_table增加写锁
LOCK TABLES test_table WRITE
UNLOCK test_table - 对于共享锁大家可能很好理解,就是多个事务只能读数据不能改数据,对于排他锁大家的理解可能就有些差别,排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。
PHP中的文件锁机制
- 说明:文件锁机制一般在单独操作文件时看不到效果,需要多人同时操作(并发)。
- 用途:若一个人在写入一个文件,另外一个人同时也打个了这个文件进行写入文件。
这情况下,很难明确谁的操作为准。因此,这个时候我们引入锁机制。若用户A在写入或者读取这个文件的时候,将文件加上共享锁。我可以读,其他人也可以读。但是,其他人不可以写。我使用独占锁/排它锁。这个文件归我了,你们都别动,除非我将文件锁进行释放。 - 锁类型:
LOCK_SH 取得共享锁定(读取的程序)
LOCK_EX 取得独占锁/排它锁定(写入的程序)
LOCK_UN 释放锁定(无论共享或独占)
LOCK_NB 当被锁定时,不阻塞,而是提示锁定。
注:加锁必须释放