MySQL innodb中的锁

mysql innodb中的锁
     InnoDB存储引擎锁的实现和Oracle非常类似,提供一致性的非锁定读、行级锁支持、行级锁没有相关的开销,可以同时得到并发性和一致性。 
     InnoDB存储引擎实现了如下两种标准的行级锁: 
共享锁(S Lock):允许事务读一行数据; 
排他锁(X Lock):允许事务删除或者更新一行数据。 
     当一个事务已经获得了行r的共享锁,那么另外的事务可以立即获得行r的共享锁,因为读取没有改变行r的数据,我们称这种情况为锁兼容。但如果有事务想获得行r的排他锁,则它必须等待事务释放行r上的共享锁――――这种情况称为锁不兼容。 



     在InnoDB Plugin之前,只能通过SHOW FULL PROCESSLIST,SHOW ENGINE INOODB STATUS等命令来查看当前的数据库请求,然后再判断当前事务中的锁的情况。新版本的InnoDB Plugin中,在INFORMATION_SCHEMA架构下添加了INNODB_TRX、INNODB_LOCKS、InnoDB_LOCK_WAITS。通过这三张表,可以更简单地监控当前的事务并分析可能存在的锁的问题。 
INNODB_TRX由8个字段组成:
     trx_id:InnoDB存储引擎内部唯一的事务ID 
     trx_state:当前事务的状态。 
     trx_started:事务的开始时间。 
     trx_requested_lock_id:等待事务的锁ID。如trx_state的状态为LOCK WAIT,那么该值代表当前的等待之前事务占用锁资源的ID. 
     若trx_state不是LOCK WAIT,则该值为NULL。 
     trx_wait_started:事务等待开始的时间。 
     trx_weight:事务的权重,反映了一个事务修改和锁住的行数。在InnoDB存储引擎中,当发生死锁需要回滚时,InnoDB存储会选 
     择该值最小的进行回滚。 
     trx_mysql_thread_id:Mysql中的线程ID,SHOW PROCESSLIST显示的结果。 
     trx_query:事务运行的sql语句。 
     通过select * from infomation_schema.INNODB_TRX;可查看 

INNODB_LOCKS表,该表由如下字段组成:
     lock_id:锁的ID。 
     lock_trx_id:事务ID。 
     lock_mode:锁的模式。 
     lock_type:锁的类型,表锁还是行锁。 
     lock_table:要加锁的表。 
     lock_index:锁的索引。 
     lock_space:InnoDB存储引擎表空间的ID号。 
     lock_page:被锁住的页的数量。若是表锁,则该值为NULL。 
     lock_rec:被锁住的行的数量。若是表锁,则该值为NULL。 
     lock_data:被锁住的行的主键值。当是表锁时,该值为NULL。 
     通过select * from information_schema.INNODB_LOCK;可查看 

INNODB_LOCK_WAIT由4个字段组成:
     requesting_trx_id:申请锁资源的事务ID。 
     requesting_lock_id:申请的锁的ID。 
     blocking_trx_id:阻塞的锁的ID。 
     通过select * from information_schema.INNODB_LOCK_WAITS;可查看。 

一致性的非锁定读:InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行Delete、update操作,这时读取操作不会因此而会等待行上锁的释放,相反,InnoDB存储引擎会去读取行的一个快照数据。快照数据是指该行之前版本的数据,该实现是通过Undo段来实现。而Undo用来事务中回滚数据,因此快照本身是没有额外开销的。此外,快照数据是不需要上锁的,因为没有必要对历史的数据进行修改。一个行可能有不止一个快照数据,所以称这种技术为行多版本技术。由此带来并发控制,称之为多版本并发控制(Multi VersionConcurrency Control, MVCC)。 
     事务的隔离级别:Read uncommitted、Read committed、Repeatable read、serializable。在Read Committed和Repeatable Read下,InnoDB存储引擎使用非锁定一致性读。然而,对于快照的定义却不同。在Read Committed事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。在Repeatable事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。                  




锁的算法:
     Record Lock:单行记录上的锁 
     Gap Lock:间隙锁,锁定一个范围,但不包含记录本身 
     Next-Key Lock:Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。更加详细的介绍可以参见这篇blog,http://www.db110.com/?p=1848 

锁的问题:
       丢失更新:经典的数据库问题,当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。    
         例: 
             事务A和事务B同时修改某行的值, 
              1.事务A将数值改为1并提交 
              2.事务B将数值改为2并提交。 
              这时数据的值为2,事务A所做的更新将会丢失。 
              解决办法:事务并行变串行操作,对更新操作加排他锁。 

        脏读:一个事务读到另一个事务未提交的更新数据,即读到脏数据。 
          例: 
              1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)        
              2.Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地! 
              3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000, 像这样,Mary记取的工资数8000是一个脏数据。 
              解决办法:脏读只有在事务隔离级别是Read Uncommitted的情况下才会出现,innoDB默认隔离级别是Repeatable Read,所以生产环境下不会出现脏读。 

        不可重复读:在同一个事务中,多次读取同一数据,返回的结果有所不同。换句话说就是,后续读取可以读到另一个事务已提交的更新数据。相反"可重复读"在同一事务多次读取数据时,能够保证所读数据一样,也就是后续读取不能读到另一事务已提交的更新数据。脏读和不可重复读的主要区别在于,脏读是读到未提交的数据,不可重复读是读到已提交的数据。 
          例: 
              1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成 
              2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务. 
              3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000 
              解决办法:读到已提交的数据,一般数据库是可接受的,因此事务隔离级别一般设为Read Committed。Mysql InnoDB通过Next-Key Lock算法避免不可重复读,默认隔离级别为Repeatable Read。 

你可能感兴趣的:(oracle,锁)