数据库事务

前言:不怕误人子弟,就怕连误都不敢!!!

一、数据库事务

简单理解就是一个操作过程,有始有终的。–>开始–结束(提交或回滚) EXP:
1.事务的开启:BEGIN
2.事务的执行:一系列操作语句
3.事务的提交或回滚:COMMIT/ROLLBACK

二、事务的特性

1.原子性 :操作原子性,要么数据全部提交,要么数据全部回滚,看重的是整个操作过程
2.一致性 :数据一致性,提交前与提交后的数据要保持一致,要么提交,要么回滚,类似于原子性,只是一致性看重的是结果
3.隔离性 :设置不同的数据库隔离界别会引发不同的数据问题(下面会详细介绍)
4.持久性 :通过日志重做的方式保证数据持久化,即一次提交,永久保存

三、事务不同隔离级别引发的不同问题

idname
1ns

脏读:

1.
BEGIN;    ------开启事务1
update table set name = 'xw' where id = 1; 	------执行更新语句
2.
BEGIN;  ------开启事务2
select name from table where id = 1------此时查出的结果为ns
COMMIT;------提交事务,返回的数据就是ns
3.COMMIT------提交事务1,此时数据库中的值已经变成了xw
注:事务1先更新数据,但事务没有提交,此时事务2查询数据,并且直接提交事务,
   此时事务1才提交事务,这种情况就会造成事务2查询的数据不准确,即为脏读。

不可重复读

1.
BEGIN;------开启事务1
select name from table where id = 1;------事务1执行查询语句,此时查询到的结果为ns
2.
BEGIN;
update table set name = 'xw' where id = 1; ------事务2执行更新语句
COMMIT;------事务2提交事务,此时数据库中的结果为xw
3.
select name from table where id = 1;------事务1
COMMIT;------此时查询的结果为xw
注:事务1先执行查询并未提交事务,事务2执行更新并提交事务,此时事务1再次查询,
   查询到的结果与第一次查询的结果将不一致,此时造成了不可重复读。

幻读

1.
BEGIN;------开启事务1
select *from table;------事务1执行查询语句,此时查询到1条数据
2.
BEGIN;------开启事务2
insert into table(2,'xw');------事务2执行了insert语句
COMMIT;------事务2提交事务,此时数据库中有两条数据
3.
select * from table;------事务1执行查询,此时查询到的结果为两条数据
COMMIT------事务1提交事务
注:事务1查询了两次,第一次结果为1条数据,第二次结果为2条数据,这种情况即为幻读。

四、四种隔离级别

Read uncommitted (读未提交):最低级别,任何情况都无法保证。
Read committed(读已提交):可避免脏读的发生。
Repeatable read (可重复读):可避免脏读、不可重复读的发生。
Serializable(串行化):可避免脏读、不可重复读、幻读的发生。

注:数据库默认的隔离级别为Repeatableread(可重复读),该情况并未解决幻读的问题,为什么为默认的呢?接下来了解下数据库Innodb引擎。

五、Innodb特性
相对于其他数据库引擎,Innodb主要的两大特性:
1.锁的级别不同
Innodb实现了行锁+表锁(特殊的行锁,锁定的是表中所有的数据行)
2.对事物的支持
先简单介绍下表锁与行锁的区别

范围比较
锁定粒度表锁>行锁
加锁效率表锁>行锁
冲突概率表锁>行锁
并发性表锁<行锁

对于并发性而言,行锁的效率远远高于表锁。
六、Innodb加锁类型
1.共享锁(读锁)
定义:多个事务可以对同一个数据共享访问,不能修改
加锁方式:LOCK IN SHARE MODE
EXP:以person表举例

idname
1ns
4xw
9xm
1.
BEGIN; ------事务1开启事务
select * from person where id = 1 LOCK IN SHARE MODE------事务1使用共享锁获取数据

在这里插入图片描述

2.
BEGIN;------事务2开启事务
select * from person where id = 1 LOCK IN SHARE MODE------事务2使用共享锁获取数据
COMMIT;
注:事务1此时并未提交事务,事务2也能查询到数据

在这里插入图片描述

3.
BEGIN;------事务3开启事务
update person  set name = 'xh' where id = 1;------事务3执行更新(增删都行)语句
COMMIT;
注:事务3在事务1并未提交事务时进行更新操作,此时事务阻塞,只有事务1提交之后,事务3才能执行通过。

在这里插入图片描述
2.排他锁(写锁)

定义:一个事务持有排他锁,其他事务均不能进行任何操作。 Innodb引擎默认将所有的DELETE、UPDATE、INSERT执行默认添加锁。
加锁方式:FOR UPDATE

EXP:

	1.
	BEGIN;------事务1开启事务
	select * from person where id = 1 FOR UPDATE;------事务1执行查询

在这里插入图片描述

2.
	BEGIN;------事务2开启事务
	select * from person where id = 1 FOR UPDATE;------事务2执行查询,此时事务2会处于等待锁的状态,除非事务1提交或者回滚。

在这里插入图片描述

注:此种情况即为排他锁,即有一个事务持有排他锁,其他事务均不能进行操作。
那么这个锁机制是什么呢?
先看几个截图
EXP1:

1.表设计(id为主键,主键是含有索引的)

在这里插入图片描述

2.事务1 查询id为1的数据,事务并未提交,并且添加了排它锁

在这里插入图片描述

3.事务2(查询id为4的数据,并且使用排他锁进行查询的,并且有结果返回)

在这里插入图片描述
总结:对比两个事务的查询结果,在事务1未提交事务的前提,事务2还可以获取到数据。(先在脑子里记下这个结果)

EXP2:
1.事务1(带有排它锁通过name查询数据,name为普通字段,没有索引)
在这里插入图片描述
2.事务2(带有排他锁通过id查询数据)
在这里插入图片描述

总结: 事务1带有排他锁通过不含索引的name字段查询数据,没有提交事务,事务2带有排他锁通过id字段查询数据,需要等待锁。

对比之前的结果,发现带有排他锁通过普通字段检索数据时,如果不提交事务,其他事务都不能进行操作;带有排他锁通过索引字段检索数据时,如果不提交事务,其他事务通过索引字段查询其他数据时,仍有返回。

对比总结:
Innodb行锁的实现:通过索引项进行检索数据时,才会进行行锁,否则进行表锁。

七、行锁算法
1.临键锁
目的:为了解决幻读(为Innodb默认的行锁算法)
使用临键锁的前提:按索引检索+检索条件为范围查找+有数据命中
实现:

idname
1ns
4xw
8xm

以上面的数据表为例: Innodb引擎默认会把该表的数据分为四个区间(左开右闭)
(-∞,1],(1,4],(4,8],(8,+∞]
select * from table where id>5
锁的区间:命中记录区间+下一个区间
该查询语句Innodb引擎会使用临键锁,默认锁住(4,8],(8,+∞]这俩区间的数据。
当这两个区间数据被锁住后,其他事务执行insert语句将会一直等待,这样就能避免幻读。

2.间隙锁

使用间隙锁的条件:按索引检索+条件为范围或者等值查询+没有数据命中
锁的范围:
向上寻找最靠近记录值得数据A作为左区间,向下寻找最靠近记录值 得数据B作为右区间,(A,B)即为锁范围
目的:解决不可重复读问题

3.记录所

使用条件:按索引检索+等值匹配+有数据命中 锁的范围:锁定当前记录 目的:解决脏读

注:本篇为学习过程中的记录,如果误,请指正。
最后,希望大家都能学以致用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值