MySQL的事务
目录
一、 MySQL事务概念
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
一般来说,事务需要满足4个条件(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
1. 原子性
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2. 一致性
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
3. 隔离性
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
4. 持久性
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
二、MyISAM和InnoDB的区别
- MySQL5.5版本默认存储引擎InnoDB存储引擎
- InnoDB 支持事务概念,MyISAM不支持事务
- InnoDB 支持行锁,MyISAM支持表锁
- InnoDB 采用聚集索引,MyISAM采取非聚集索引
- InnoDB B+树 子叶子节点存放整行数据,MyISAN B+树 叶子节点存放数据文件对应的物理地址
- InnoDB辅助索引,如果返回列,则表示没有对应的数据,则需要从主键索引查询,需要查询两次(回表)
- InnoDB不支持外键,MyISAM不支持外键
- InnoDB不保存表的具体行数,count()查询需要全表扫描,MyISAM保存了整个表的行数,count()查询效率非常高
- innoDB最小的锁粒度是行锁,MyISAM最小的锁粒度是表锁
- InnoDB采用行锁,支持并发性,MyISAM采用表锁,支持并发性比较弱
三、MySQL锁的分类
1.从锁的性能角度主要分为乐观锁(自旋)和悲观锁
2.从锁的粒度角度主要分为读写锁(共享锁)、重入锁、排它锁、公平锁与非公平锁
3.从数据库粒度角度主要分为行锁与表锁
表锁:每次操作锁住整张表,开销小,加锁快;锁定粒度大,发生锁冲突的概率最高,并发度最低
行锁:每次操作锁住一行数据,开销大,加锁慢;会出现思索;锁定粒度最小,发生锁冲突的概率最低,并发度最高
表锁(所有的数据都锁):多个线程在同时对一张表(不同的行数据)做写的操作时,最终只会有一个线程获取到表锁,导致其他线程无法对该表做写的操作。
行锁:多个线程在同时对一行数据做写的操作,最终只会有一个线程获取到该行锁——InnoDB默认行锁策略
目的:保证数据一致性问题
手动新增表锁
lock table 表名称 read(write),表名称2 read(write);
查看表上加过的锁
show open tables;
删除表锁
unlock tables;
1. MyISAM表锁实现原理
- 对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读操作,但会阻塞对同一表的写操作。只有当读锁释放后,才能执行其他进程的写操作。在锁释放前不能读其他表。 (共享锁)
- 对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。在锁释放前不能写其他表。(独占锁)
总结:
表锁,读锁会阻塞写,不会阻塞读。而写锁则会把读写都阻塞。
表锁的加锁/解锁方式:MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作 (UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。
2. InnoDB行锁实现原理
- 每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
- InnoDB与MYISAM的最大不同有两点:
支持事务(TRANSACTION)
支持行级锁—-事务关联
四、for update(排它锁)
for update是一种行级锁,又叫排它锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式锁表,一直到提交或复原该事务为止。行锁永远是独占方式锁。
而select … for update 语句是我们经常使用手工加锁语句。在数据库中执行select … for update ,大家会发现会对数据库中的表或某些行数据进行锁表,在mysql中,如果查询条件带有主键,会锁行数据,如果没有,会锁表。
五、悲观锁与乐观锁实现
悲观锁比较悲观,多线程同时对同一行数据修改的时候,最终只有一个线程修改成功。
Innodb引擎自带行锁机制,会让我们的用户线程阻塞。
乐观锁:比较乐观,多线程同时对同一行数据修改的时候,如果没有获取到行锁的线程,
修改失败的话,会采用自旋的方式不断重试,一般采用cas实现。
六、MySQL间隙锁
1. 间隙锁基本概念
间隙锁是一个在索引记录之间的间隙上的锁。
2. 间隙锁的作用
在MySQL的innoDB引擎中,如果操作的是一个区间的数据,会锁住这个区间所有的记录,即使这个记录不存在,这个时候另一个会话去插入这个区间的数据,就必须等待上一个结束。
主键索引或者唯一索引会使用间隙锁吗?
- 如果where条件都命中的情况下,则不会发生间隙锁,只会增加记录锁
- 如果where条件部分命中或者全部没有命中的情况下,则使用间隙锁 (范围查询)
3. 如何避免行锁升级表锁
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则都会从行锁升级为表锁。
使用 for update 查询语句 where id=
行锁–根据主键id(主键索引)有关系(索引字段)
4. 优化注意事项
- 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
- 尽可能减少检索条件范围,避免间隙锁
- 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131294.html