本文虽为原创,但是内容多是从网上东一块西一块引用过来的,文章可以看做是学习记录


锁的类型有三种: 

共享(S)锁:多个事务可封锁一个共享页;任何事务都不能修改该页; 通常是该页被读取完毕,S锁立即被释放。 


排它(X)锁:仅允许一个事务封锁此页;其他任何事务必须等到X锁被释放才能对该页进行访问;X锁一直到事务结束才能被释放。 


更新(U)锁:用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的页将要被更新时,则升级为X锁;U锁一直到事务结束时才能被释放。





例4:(死锁的发生)


----------------------------------------


T1:


begin tran


select * from table (holdlock) (holdlock意思是加共享锁,直到事物结束才释放)


update table set column1='hello'




T2:


begin tran


select * from table(holdlock)


update table set column1='world'




假设T1和T2同时达到select,T1对table加共享锁,T2也对table加共享锁,当T1的select执行完,准备执行update时,根据锁机制,T1的共享锁需要升级到排他锁才能执行接下来的update.在升级排他锁前,必须等table上的其它共享锁释放,但因为holdlock这样的共享锁只有等事务结束后才释放,所以因为T2的共享锁不释放而导致T1等(等T2释放共享锁,自己好升级成排他锁),同理,也因为T1的共享锁不释放而导致T2等。死锁产生了。


上面的例子是针对SqlServer的。




共享锁即在select 时自动产生,排它锁在insert,update以及delete时自动产生。


(mysql不完全是这样的)




相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。




MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。在本书的示例中,显式加锁基本上都是为了方便而已,并非必须如此。






如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。


意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。


共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。


排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。




用SELECT ... IN SHARE MODE获得共享锁,主要用在需要数据依存关系时来确认某行记录是否存在,并确保没有人对这个记录进行UPDATE或者DELETE操作。但是如果当前事务也需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录后需要进行更新操作的应用,应该使用SELECT... FOR UPDATE方式获得排他锁。




举例说明下意向共享锁,比如一个事务t执行了这样一个语句:select * from table lock in share model ,如果这个语句执行成功,就对表table上了一个意向共享锁。lock in share model就是说事务t1在接下来要执行的语句中要获取S锁。如果t1的select * from table lock in share model执行成功,那么接下来t1应该可以畅通无阻的去执行只需要共享锁的语句了。意向排它锁的含义同理可知,上例中要获取意向排它锁,可以使用select * from table for update 。



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






由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。



死锁问题


​http://blog.knowsky.com/260327.htm​



索引

有以下四种:


普通索引(可以有重复)




唯一索引


它与前面的普通索引类似,不同的就是:普通索引允许被索引的数据列包含重复的值。而唯一索引列的值必须唯一,但允许有空值。




主键索引(就是加在主键上的唯一所有)


它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:




组合索引


为了形象地对比单列索引和组合索引,为表添加多个字段:


CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT NULL,   city VARCHAR(50) NOT NULL,   age INT NOT NULL  ); 为了进一步榨取MySQL的效率,就要考虑建立组合索引。就是将 name, city, age建到一个索引里:




并发

并发带来的问题


1 脏读 


   1 sessionA写了一条数据(并没有自动提交)


   2 sessionB去读,就读到sesionA更新的数据


   3 sessionA rollbacke


   那么sessionB就是脏读#




2 不可重复读


   1 sessionA读到一条数据


   2 sessionB修改了那条数据


   3 sessionA再读那条数据的时候,发现与第一次读到的不一样了#(步骤1与步骤3是在一个事务里的)


   这就是不可重复读#




3  幻读


   1 sessionA通过查询条件在一张表里查到了4条数据


   2 sessionB更新了相同条件的数据#


   2 sessionA再次使用相同的查询条件发现读到数据总数不是4#(步骤1与步骤3是在一个事务里的)


   这就是幻读




数据库的隔离级别一般有四种#


分别是


read uncommitted 读取未提交内容


read committed 读取提交内容


repeatable read 可重复读


serializable 可串行化


mysql默认的隔离比较是repeatable read


隔离比较与并发问题的关系如下:


数据库的一些基本概念_共享锁





另外


InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了幻读问题。


MVCC只能工作在repeatable read与read committed级别





​MySQL数据库事务隔离级别(Transaction Isolation Level)​


​数据库隔离级别以及mysql隔离级别 ​




关于MVCC

从上面的描述可以看到,在查询时要符合以下两个条件的记录才能被事务查询出来: 


1) 删除版本号 大于 当前事务版本号,就是说删除操作是在当前事务启动之后做的。 


2) 创建版本号 小于或者等于 当前事务版本号 ,就是说记录创建是在事务中(等于的情况)或者事务启动之前。


​mysql的mvcc(多版本并发控制)​