李琪的技术专栏 System Research

MySql基础复习(1)--事务

2020-05-08
Clear Li

阅读:


image-20200508203659396

先从事物开始整理

事务的四大特性

(1)原子性

​ 这个是最容易理解的,原子性是指事务包含的所有操作要么全部成功,要么全部失败。

(2)一致性

​ 一致性是指事务必须从数据库的一个状态变换到另一个一致性状态。就是说一个事务执行之前和之后都必须处于一致性状态。。比如两个人转账,无论怎么转账,钱的总量不能变化。

(3)隔离性

​ 隔离性是指当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰。做到这一点需要数据库的隔离级别来实现,之后再写吧。

(4)持久性

​ 持久性是指,一旦事务被提交,对数据库的数据改变就是永久性的,数据库系统遇到故障的情况下也不会丢失提交事务的操作。这个我的理解就是,当提交事务时,只有真正保存数据后,数据库才会将事务成功提交返回给用户。否则返回事务提交失败。

数据库引擎

image-20200508165009615

数据库读取问题

image-20200508174259752

脏读

一个事务读取到另一个事务未提交的更新数据。

image-20200508170446359

在事务 A,B 中,事务 A 在时间点 2,4 分别对 user 表中 id = 1 的数据进行了查询。

但是事务 B 在时间点 3 进行了修改,导致了事务 A 在 4 中的查询出的结果其实是事务 B 修改后的。这样就破坏了数据库中的隔离性。

不可重复读

在同一个事务中,多次读取同一个数据返回的结果不同,不可重复读和脏读不同的是这里的读取是已经提交过后的数据

image-20200508171132277

在事务 B 中提交的操作在事务 A 第二次查询之前,但是依然读到了事务 B 的更新结果

幻读

一个事务读到另一个事务已提交的insert数据

image-20200508171322105

在事务 A 中查询了两次 id 大于 1 的,在第一次 id 大于 1 查询结果中没有数据,但是由于事务 B 插入了一条 id = 2 的数据,导致事务 A 第二次查询时能查到事务 B 中插入的数据。

事务中的隔离性

image-20200508174629769

image-20200508172117676

InnoDB锁的类型

S 共享锁

又叫读锁,其他事务可以继续加共享锁,但是不能继续加排他锁

X 排他锁

又叫写锁,一旦加了写锁后,其他事务就不能加锁了

解释:对于共享锁就是多个事务只能读数据不能修改数据,但是对于排他锁,并不是把一行数据锁住之后其他事务就不能读取或者修改该数据,是加上这个锁之后其他事务就不能在加上其他的锁了。mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型

共享锁测试

加共享锁

image-20200508201015057

然后我们在另一个窗口测试更改数据,结果是被阻塞。只有在加锁时提交之后释放锁才会放行

image-20200508201051655

排他锁测试

排他锁加锁(没有commit就没有释放锁)

image-20200508200302299

其他线程再尝试加锁(发现被阻塞)

image-20200508200402203

直接查询不加锁是可以查询的

image-20200508200512682

由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会执行Table Lock (将整个资料表单给锁住)。

1 脏读解决办法:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这 样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更 无权参与进来读写,这样就防止了脏读问题。这里就是在读取的时候加共享锁防止其他会话更改数据,在更改数据时加排他锁,

​ 但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改 完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。与上面方法的不同就是在读取的时候加的共享锁的释放范围是在会话结束的时候释放

2 不可重复读:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题 3 幻读问题:采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻影读问题,

回滚日志

是用来回滚操作所使用的日志。回滚日志会在没有事务用到这些日志的时候,被删除。而且回滚日志会占用空间。因此尽量不要使用长事务长事务意味着系统里面会存在很老的事务视图。

长事务

长事务就是只开启事务而立即不提交或回滚的事务。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致占用大量的存储空间。第二长事务还会占用锁资源也会拖垮整个库。

set autocommit = 0

上面的sql会将这个线程的自动提交关闭掉,因此可能会造成事务的持续存在。

因此建议使用set autocommit = 1,通过显式语句的方式来启动事务。假如有多次的开启事务的情况那么提交时使用如下sql

commit work and chain

Similar Posts

下一篇 树结构