mysql锁

锁:保证数据的一致性

1.表级锁定(table-level)
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并大度大打折扣。
使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。


MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)
表共享读锁:测试中,即当运行lock table user_myisam read;时,insert ,update等操作无法运行 ,运行 unlock tables; 之后,才能操作成功

表独占写锁:测试中,即当运行lock table user_myisam write;时,select等操作无法运行 ,运行 unlock tables; 之后,才能操作成功

如何加表锁
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁

MyISAM的锁调度:
前面讲过,MyISAM存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM表的读锁,同时另一个进程也请求同一表的写锁,MySQL如何处理呢?答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前!这是因为MySQL认为写请求一般比读请求要重要。这也正是MyISAM表不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。这种情况有时可能会变得非常糟糕!幸好我们可以通过一些设置来调节MyISAM 的调度行为。
通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。

 


2.行级锁定(row-level)
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。

表锁:开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高

MyISAM:支持表锁
InnoDB:支持行锁和表锁,支持事务

事务:ACID属性:原子性,一致性,隔离性,持久性
并发事务的问题:
脏读:事务1修改数据,未提交,事务2读取了修改后的数据
不可重复读:事务1读取数据后,过段时间再次读取,发现数据已经改变
幻读:事务1读取数据后,事务2插入数据,事务1再次读取,发现数据变多

处理方式:事务隔离
事务隔离级别:
未提交读(Read uncommitted),已提交度(Read committed),可重复读(Repeatable read),可序列化(Serializable)

读数据一致性及允许的并发副作用
隔离级别
读数据一致性 脏读 不可重复读 幻读
未提交读(Read uncommitted)最低级别,只能保证不读取物理上损坏的数据 是 是 是
已提交度(Read committed)语句级 否 是
是可重复读(Repeatable read)事务级 否 否 是
可序列化(Serializable)最高级别,事务级 否 否 否

行锁:
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

 

/////////////////////////
InnoDB行锁实现方式
InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
//////////////////////////

MyISAM更适合做以查询为主的表,InnoDB更适合做更新,新增等操作的表

 

乐观锁姐悲观锁不是数据库自带的一种锁,是一种并发控制的技术手段。

乐观锁:

数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。

操作方法:使用时间戳或version版本号

例:

select (id,email,version) from user where id=1;

update user set email='111@qq.com',version=version+1 where id=id and version=version

用时间戳也一样。

悲观锁:

在对任意记录进行修改前,先尝试为该记录加上排它锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。 具体响应方式由开发者根据实际需要决定。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常

例子:

begin;
select email from user where id=1 for update;
insert into user (id,email) values (2,'22@qq.com');
update user set status=2 where id=1;
commit;

 

posted @ 2018-06-07 14:22  莫弦然  阅读(119)  评论(0编辑  收藏  举报