Mysql InnoDB引擎的读锁

Mysql官方手册读锁说明

如果,在一个相同的事务中,你查询数据,然后插入/更新与此数据相关的数据,那个通常的SELECT语句不会给我们足够的保护.因为在我们当前事务的SELECT和UPDATE之间的时间段内,其他的事务可能会更新/删除我们刚刚读取到的行.而我们根本不会察觉.

InnoDB支持两种类型的读锁,可以给我们提供足够的安全.

1.SELECT ... LOCK IN SHARE MODE 

这是共享锁,在读取的任何数据上设定一个共享模式的锁.其他事务可以读取这些数据.但是不能修改这些数据,除非我们设定锁的事务提交了.如果我们查询的数据正被其他事务修改,而且这些事务还没有提交,那么我们的查询会一直等待,直到这些事务提交,然后我们的查询就使用这些最新的数据.

注意:要想正确使用SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE,必须关闭自动提交事务(set autocommit = 0),或者手动开启一个事务(begin/start transaction),如果不开启事务,那些查询到的数据不会被加锁

2.SELECT ..... FOR UPDATE;

这是独占锁,会阻塞其他尝试修改的事务、使用SELECT....LOCK IN SHARE MODE的事务和一些事务隔离级别的事务(如FOR UPDATE)。

举例SELECT...FOR UPDATE,此方法要读取最新的结果

第一种情况,事务1开启事务并查询某条记录接着然后执行随后的动作,

事务1开启事务并查询一条记录

注意事务1并没有提交,此时事务2企图UPDATE此条记录

然而由于事务1还没有提交,事务2的UPDATE要等待,此刻用事务1再次查询此条记录,看记录有没有被改

上图可以发现,password并没有变

然后,事务1等了一会儿,终于提交了

这时候去看事务2,由于事务1commit后释放了锁,事务2就得到了锁,立刻返回了结果:

然后我再查询此条记录,发现终于更新为333了

在业务场景中,如果两个事务都使用lock in share mode,然后进行更新操作。如两个事务都获取了共享锁,在释放锁(commit或者roll back)之前都去执行update,由于update操作需要等待对方释放锁,就造成了死锁(deadlock),这是业务不允许的,所以一般使用FOR UPDATE让事务获取独占锁,完成事务后,才允许其他事务获取锁。

注意:

1.如果开启了事务1,在事务1的过程中,事务1执行SELECT(尚未提交),事务2修改了数据并提交,此时,就算事务1再次执行SELECT,事务1也不会查到事务2所做的改动。除非重新开启事务。

2.加共享/独占锁的前提是:其他事务已经释放了独占锁

3. 关于 AUTOCOMMIT

因为涉及到事务,所以InnoDB才有自动提交这一说。虽然Myisam引擎中使用SET AUTOCOMMIT不会报错,但是由于没有事务功能,使用这条语句无效,没意义。

在InnoDB中,所有的用户行为都是在事务中发生,如果自动提交允许,每个SQL语句在它自己上形成一个单独的事务,mysql总是带着允许自动提交来开始一个新的连接.

但是,如果自动提交模式被用"SET AUTOCOMMIT = 0"关闭了,那么我们可以认为一个用户总是有一个事务在开着.

"COMMIT"或"ROLLBACK"语句结束当前事务并且开始新的事务,一个"COMMIT"语句意味着在当前事务中做的改变被生成永久的,并变成其他用户可见的.而一个"ROLLBACK"则是撤销所有当前事务做的修改.

时间: 2024-08-07 09:38:59

Mysql InnoDB引擎的读锁的相关文章

MySQL Study之--MySQL innodb引擎备份工具XtraBackup之一(Install)

MySQL Study之--MySQL innodb引擎备份工具XtraBackup之一(Install) Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品. Xtrabackup有两个主要的工具:xtrabackup.innobackupex (1)xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表 (2)innobackupex-1.5

巧用MySQL InnoDB引擎锁机制解决死锁问题(转)

该文会通过一个实际例子中的死锁问题的解决过程,进一步解释innodb的行锁机制 最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深. 案例如下: 在使用Show innodb status检查引擎状态时,发现了死锁问题: *** (1) TRANSACTION: TRANSACTION 0 677833455, ACTIVE 0 sec, process no 11393, OS thread id 278546 starti

mysql innodb 引擎内存分配项

MySQL做为最流行的开源数据库,innodb在5.6开始已成为默认引擎,在5.7中系统吧引擎也有myisam改为innodb,可以看出innodb引擎现在已经可以满足绝大部分的业务需求,内存分配直接影响MySQL整体运行效率,有innodb_buffer,还有各种cache_size,这些选项都需要合理分配,合理利用服务器有限的内存让MySQL跑的更嗨皮,直接影响的选项有下面几个: innodb_buffer_pool_size:缓冲区,存放表数据.索引数据,大小至关重要,直接影响sql执行时

MySQL innoDB引擎锁机制(一) —— 行锁和表锁

我们都知道,MyISAM引擎使用的是表锁,而innoDB最小粒度为行锁.但在实际使用中我们有时发现就算我们操作的是不同行的数据,还是会发生锁表.我们先来看一个例子. session1开启事务并更新id=1的数据: session2开启事务,并更新id=2的数据,但session2被阻塞了: 不是说innoDB支持行锁吗,我们这里明明更新的不是同一条数据,为什么还会被阻塞.其实这是因为MySQL innoDB给数据加锁的方式和oracle不一样.oracle是给这条数据行加锁,而innoDB是给索

mysql InnoDB引擎 共享表空间和独立表空间(转载)

PS:innodb这种引擎,与MYISAM引擎的区别很大.特别是它的数据存储格式等.对于innodb的数据结构,首先要解决两个概念性的问题: 共享表空间以及独占表空间. 1.什么是共享表空间和独占表空间 共享表空间以及独占表空间都是针对innodb表的数据存储而言的,ibdata1为innodb引擎的存储数据与索引的数据文件,ib_logfile0与ib_logfile1为innodb引擎使用的日志文件共享表空间: mysql服务器中所有数据库的innodb表(数据,索引)全部放在一个文件中,默

[MySQL] innoDB引擎的主键与聚簇索引

mysql的innodb引擎本身存储的形式就必须是聚簇索引的形式 , 在磁盘上树状存储的 , 但是不一定是根据主键聚簇的 , 有三种情形: 1. 有主键的情况下 , 主键就是聚簇索引 2. 没有主键的情况下 , 第一个非空null的唯一索引就是聚簇索引 3. 如果上面都没有 , 那么就是有一个隐藏的row-id作为聚簇索引 大部分情况下 , 我们建表的时候都会创建主键 , 因此大部分都是根据主键聚簇的 当我们根据主键字段来进行查询时 , 效率是最高的 , 不需要二次查找 , 直接主键字段查询索引

Mysql Innodb 引擎优化

介绍: InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎.InnoDB锁定在行级并且也在SELECT语句 提供一个Oracle风格一致的非锁定读.这些特色增加了多用户部署和性能.没有在InnoDB中扩大锁定的需要,因为在InnoDB中行级锁定适合非常 小的空间.InnoDB也支持FOREIGN KEY强制.在SQL查询中,你可以自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也可以混合. Innodb 的创始人:Hei

MySQL InnoDB引擎索引长度受限怎么办?

大家应该知道InnoDB单列索引长度不能超过767bytes,联合索引还有一个限制是长度不能超过3072. mysql> CREATE TABLE `tb` ( ->   `a` varchar(255) DEFAULT NULL, ->   `b` varchar(255) DEFAULT NULL, ->   `c` varchar(255) DEFAULT NULL, ->   `d` varchar(255) DEFAULT NULL, ->   `e` var

InnoDB 引擎独立表空间 innodb_file_per_table

使用过MySQL的同学,刚开始接触最多的莫过于MyISAM表引擎了,这种引擎的数据库会分别创建三个文件:表结构.表索引.表数据空间.我们可以将某个数据库目录直接迁移到其他数据库也可以正常工作.然而当你使用InnoDB的时候,一切都变了. InnoDB 默认会将所有的数据库InnoDB引擎的表数据存储在一个共享空间中:ibdata1,这样就感觉不爽,增删数据库的时候,ibdata1文件不会自动收缩,单个数据库的备份也将成为问题.通常只能将数据使用mysqldump 导出,然后再导入解决这个问题.