MySQL:事务的概念、事务的隔离级别 - Go语言中文社区

MySQL:事务的概念、事务的隔离级别


一、事务的基本概念和操作流程

Transaction
通常情况下在某些业务:如银行转账等,这样的业务他不是由一个SQL语句构成而是多个或多组的SQL构成,那么这样的一个过程,我们称之为一组事务。

事务的特征(ACID)

A 原子性(Atomicity):事务是最小的单位,不可再分
C 一致性(Consistency):事务在DML语句操作时,要保证同时成功同时失败
I 隔离性(Isolation):事务和事物之间互不干扰
D 持久性(Durability):完成事务后,最终要把数据库表的更改内容持久化到磁盘上

开启事务 start Transaction
关闭事务 End Transaction
提交事务 commit
回滚事务 rollback
设置保存点 savepoint

事务的简单实现

public static void main(String[] args){
	Connection conn = null;
	PreparedStatement ps1 = null;
	PreparedStatement ps2 = null;
	Savepoint sp = null;
	try{
		conn = JDBCUtil.getConnection();
		//将自动提交事务禁用
		conn.setAutoCommit(false);
		//设置保存点
		sp = conn.setSavepoint("A");
		ps1 = conn.prepareStatement("update tb1 set salary = salary + 1000 where username = ?");
		ps1.setString(1,"lucy");
		ps2 = conn.prepareStatement("update tb1 set salary = salary - 1000 where username = ?");
		ps2.setString(1,"lisi");
		ps1.executeUpdate();
		ps2.executeUpdate();
		
	} catch (Exception e){
		try{
			conn.rollback(sp);
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		e.printStackTrace();
	}finally{
		try {
			conn.commit();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

二、事务的隔离级别

SQL事务隔离级别

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
不可重复读(repeatable-read)
串行化(Serializable)

事务的并发问题:
脏读: 事务A读取了事务B的更新,然后B回滚操作,此时A读到的数据就是脏数据。
不可重复读: 事务A多次读取同一数据,事务B在事物A多次读取的过程中,对数据作了更新并提交,导致事物A多次读取同一数据,结果不一致。
幻读: 系统管理员A将数据库中学生的成绩分数改为ABCD四个等级,但是系统管理员B此时插入了一条具体分数的记录,当管理员A修改结束后发现还有一条记录没有修改过来,好像出现了幻觉一样。

MySQL默认的事物隔离级别为repeatable-read

在这里插入图片描述

2.1 读未提交

1)设置客户端A当前事物模式为read uncommitted

在这里插入图片描述
可看出当前 lisi 的 age 是19,我们进行修改,但不提交

在这里插入图片描述
2)新建一个客户端B并设置事务模式,进行查询tb1,虽然客户端A并未提交,但是此时 lisi 的 age 已经为20

在这里插入图片描述
一旦此时客户端A的事物由于某些原因进行回滚,则此时客户端B查到的数据就是脏数据。

3)当客户端B执行更新语句时,lisi 的年龄并没有变成21而是变成了20。但是客户端B本身并不知道客户端A已经回滚操作,引发问题。
在这里插入图片描述

2.2 读已提交

1)打开客户端A,设置事务模式read committed,查询tb1的所有记录:
在这里插入图片描述
2)在客户端A的事物提交之前,打开另一个客户端B,更新表tb1:
在这里插入图片描述

3)客户端B没有commit,此时客户端A再次进行查询时,数据没有显示变化,解决了脏读问题:
在这里插入图片描述

4)客户端B将修改过的事务进行提交:

在这里插入图片描述

5)客户端A再次进行查询,此时查询数据已经不同,但是产生了不可重复读的问题:
在这里插入图片描述

2.3 可重复读

1)打开客户端A,将其事物设置为可重复读(repeatable read),并查询现在tb1表中的数据:
在这里插入图片描述
2) 新建一个客户端B,更改tb1中的数据,并进行提交:
在这里插入图片描述

3)此时客户端A再次进行查询查询到的数据与原来相同,没有发生不可重复读现象:

在这里插入图片描述

4)在客户端A中,执行update tb1 set age = age - 1 where username = ‘lisi’; 此时 age 没有变为19而是变为21,是由于此时的值是由客户端B中的值age = 22,来计算的,所以是21。

在这里插入图片描述
那么此时数据的一致性被破坏了吗??
答案是:并没有。
可重复的隔离级别下使用了MVCC机制,select操作下不会更新版本号,是快照读(历史版本);insert,update 和 delete 会更新版本号,是当前读(当前版本)。
接下来我们来验证一下:

5)用start transaction; 重新打开客户端B,插入一条数据后再次进行提交:
在这里插入图片描述
6)客户端A进行查询,没有出现增加的信息,可知并没有出现幻读现象

在这里插入图片描述

注意:

  1. 隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能影响也越大;
  2. 隔离级别为读提交时,写数据只会锁住相应的行;
  3. 可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
  4. 当为串行化时,读写数据都会锁住整张表。
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_44668555/article/details/107367783
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢