1

一.前言

  事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,数据库能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。
  在深入了解今天的主题之前,需要了解事务的有哪些特性? 事务有四大特性,简称ACID。

 

1. 原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。比如在同一个事务中的SQL语句,要么全部执行成功,要么全部执行失败。

2. 一致性(Consistency)

一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
例如:A+B=100,AB和的状态必须始终保持100。若A=80,则B=20,若A=70,则B=30,他们的和在事务结束前后必须是一致的。

3. 隔离性(Isolation)

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离

4. 持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

二.数据丢失

 先回忆一下java多线程下的安全性,假设有一变量count初始值为100,此时有线程A和线程B同时对变量count进行操作。线程A进行操作: count = count +1,在线程A赋值之前,CPU的执行权切换到线程B,此时线程B读取到的count仍然为100,线程B进行操作: count = count +2。
 那么出现的问题就显而易见了,最后执行操作的线程回覆盖前者。而我们在java中的通常做法是给代码块加锁或者变量定义为AtomicInteger类型的原子性变量。回到mysql,该如何实现呢?

假设有一银行账户count,小明和小强对其同时进行操作。如下图:
数据丢失

为了保证小明在存款时小强不能取现,或者小强在取现时小明不能存款,需要做一个互斥操作!即需要加一个排他锁(Exclusive Lock) , 简称X锁。如下图:
图片描述

三.数据隔离

  • 脏读

  脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
脏读前

 由于只在写数据的时候加锁但并未在读数据的时候加锁,导致小强读取到了回滚之前的数据。解决方案显而易见,和上面一样加一个X锁不就得了吗?但是仅仅读取数据就加X锁,有点影响性能。 所以,这里为此有专门针对于读数据的锁,即共享锁(Share lock),简称S锁。当一个数据加了X锁, 就没法加S锁, 同样加了S锁, 就没法加X锁。
脏读后

  • 不可重复

 不可重复读指在一个事务内读取表中的某一行数据,多次读取结果不同。
不可重复

 如图所述,解决脏读的方案非常简单,在同一事务读取数据时只有把数据读取完才释放锁即可!

  • 幻读

  虚读(幻读)是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
 一个事务用Where子句来检索一个表的数据,另一个事务插入一条新的记录并且符合Where条件,这样,第一个事务用同一个where条件来检索数据后,就会多出一条记录!例如:

目前工资为1000的员工有10人。
1.事务1,读取所有工资为1000的员工。
2.这时事务2向employee表插入了一条员工记录,工资也为1000
3.事务1再次读取所有工资为1000的员工 共读取到了11条记录。
  • 总结

不可重复&幻读 区别

不可重复读的重点是修改 : 同样的条件, 你读取过的数据,再次读取出来发现值不一样了

幻读的重点在于新增或者删除: 同样的条件, 第 1 次和第 2 次读出来的记录数不一样.

隔离性

隔离性总结

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

mysql数据库默认的事务隔离级别是:Repeatable read(可重复读)
mysql数据库设置事务隔离级别:
set transaction isolation level 隔离级别名

四.测试

查看当前数据库的事务隔离级别:
select @@tx_isolation;
结果如下图,可以清晰的发现当前数据库默认的隔离级别为:REPEATABLE-READ
查看数据库隔离级别

为了验证上面聊到的数据库因为隔离级别的不同而造成的不同后果,开启以下演示!下面以脏读为例:

1.更改当前数据库的事务隔离级别,并开启事务。

set transaction isolation level  read uncommitted;
start transaction;

2.在当前窗口A查询count的值,结果为100
3.重新开启一个窗口B,开启事务并且更新数据

start transaction;
update account set count = count + 20 where id = 1;

4.切回到窗口A查询count的值,结果为120 ,此时读取到了窗口B中尚未提交的事务。
演示

至于其他演示,本文就暂不做赘述,方法都大同小异。

 本人以笔记总结为主,简单概述了事务的四大特性及事务的隔离级别。最后将以幻读为切入点,下篇文章讲讲MVCC的的概念


时光沉旧了少年
95 声望23 粉丝

有些人不离开你,你永远都长不大