事务和锁
2022/7/22 23:31:00
本文主要是介绍事务和锁,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、事务
ACID原则
即Atomicity(原子性) Consistency(一致性), Isolation(隔离性), Durability(持久性)
原子性:要执行的事务是一个独立的操作单元,要么全部执行,要么全部不执行
一致性:事务的一致性是指事务的执行不能破坏数据库的一致性,一致性也称为完整性。一个事务在执行后,数据库必须从一个一致性状态转变为另一个一致性状态。
隔离性:多个事务并发执行时,一个事务的执行不应影响其他事务的执行,SQL92规范中对隔离性定义了不同的隔离级别:
持久性:事务对数据库的修改是持久存在。
事务隔离级别
sql隔离标准:
READ UNCOMMITTED(读未提交)
在该级别中,事务中的修改即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据称之为脏读(Diryt Read)。这个级别会导致很多问题,性能也不会比其他级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。
READ COMMITED(读已提交)
大多数数据库系统的默认隔离级别都是该级别(但MySQL不是)。该级别满足隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。也就是说,一个事务从开始直到提交前,所做的修改对其他事务都是不可见的。这个级别有时候也叫作不可重复读,因为*两次执行同样的查询,可能会得到不一样的结果。
REPEATABLE READ(可重复读)
该级别是MySQL的默认事务隔离级别,解决了脏读的问题,并保证了在同一个事务中多次读取同样的记录的结果是一致的。理论上可重复读还是无法解决另外一个幻读的问题。幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,之前的事务再次读取该范围的记录时,会产生幻行。InnoDB存储引擎通过多版本并发控制(MVCC)解决了该问题。
SERIALIZABLE(可串行化)
该级别是最高的隔离级别,它通过强制事务串行执行,避免了前面所说的幻读问题。简单来说,该级别会对读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。
注意:mysql第三四级别(REPEATABLE READ(可重复读)、SERIALIZABLE(可串行化)已经解决了幻读问题
设置事务隔离级别:
set session transaction isolation level read uncommitted;
事务开启
mysql执行SQL语句会被默认开启事务,插入SQL语句,再提交事务。
也可以手动开启:
1.START TRANSACTION 或 BEGIN 开始新的事务 COMMIT 提交当前事务 ROLLBACK 回滚当前事务
2.SET autocommit = 0;默认情况下 autocommit = 1,是自动提交事务的。autommit 是 session 级别的,就是当前连接更改了 autocommit,对其他连接没有影响。设置 autocommit 之后,本次连接的所有 sql 都是事务的形式,比如每次 commit 提交。
开启手动提交后,会出现隐式提交事务:
保存点
如果你开启了一个事务,并且已经敲了很多语句,忽然发现上一条语句有点问题,你只好使用ROLLBACK语句来让数据库状态恢复到事务执行之前的样子,然后一切从头再来,总有一种一夜回到解放前的感觉。
MYSQL提出了一个保存点(英文:savepoint)的概念,就是在事务对应的数据库语句中打几个点,我们在调用ROLLBACK语句时可以指定会滚到哪个点,而不是回到最初的原点。
定义保存点的语法如下:
SAVEPOINT 保存点名称;
当我们想回滚到某个保存点时,可以使用下边这个语句(下边语句中的单词WORK和SAVEPOINT是可有可无的)
ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称;
不过如果ROLLBACK语句后边不跟随保存点名称的话,会直接回滚到事务执行之前的状态。
如果我们想删除某个保存点,可以使用这个语句:
RELEASE SAVEPOINT 保存点名称;
二、锁
锁分类
从锁的粒度,我们可以分成两大类:
表锁 :开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
不同的存储引擎支持的锁粒度是不一样的:InnoDB行锁和表锁都支持、MyISAM只支持表锁!InnoDB只有通过索引条件检索数据才使用行级锁,否则,InnoDB使用表锁也就是说,
表锁其实我们程序员是很少关心它的:
- 在MyISAM存储引擎中,当执行SQL语句的时候是自动加的。
- 在InnoDB存储引擎中,如果没有使用索引,表锁也是自动加的。
锁用途:
- 共享锁(S锁、读锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。即多个客户可以同时读取同一个资源,但不允许其他客户修改。
- 排他锁(X锁、写锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的读锁和写锁。写锁是排他的,写锁会阻塞其他的写锁和读锁
间隙锁GAP
当我们用范围条件检索数据而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合范围条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在 的记录,叫做“间隙(GAP)”。InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。例子:假如emp表中只有101条记录,其empid的值分别是1,2,...,100,101
InnoDB使用间隙锁的目的有2个:
- 为了防止幻读(Repeatable read隔离级别下再通过GAP锁即可避免了幻读) ,会让插入间隙的sql语句阻塞,数据插入不了
- 满足恢复和复制的需要:MySQL的恢复机制要求在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读
死锁
2+个线程在执行过程中, 因争夺资源而造成的相互等待的现象,若无外力作用,它们将无法推进下去。
Use SHOW INNODB STATUS来确定最后一个死锁的原因。
死锁避免:
1.以固定的顺序访问表和行
2.大事务拆小,大事务更容易产生死锁
3.在一次事务中尽可能做到一次锁所需要的所有资源,减少死锁概率
4.用更低的隔离级别;
5.使用更少的锁定。
这篇关于事务和锁的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南