MySQL的事务与隔离级别

1. 什么是事务?

数据库中的事务是指对数据库执行一批操作。

那对MySQL的一批操作A 和 其他的对MySQL的一批操作B 有什么不同的?比如说这批操作集合A想要该集合中的所有操作都成功,否则就都失败。那要想有这个保证,那就需要事务了。

事务在执行的时候,会提供专门的属性保护,包括原子性一致性隔离性持久性

2.事务的几个特性(ACID)

ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。

原子性(Atomicity)

事务的整个过程如原子操作一样,最终要么全部成功,或者全部失败,这个原子性是从最终结果来看的,从最终结果来看这个过程是不可分割的。

一致性(Consistency)
一个事务必须使数据库从一个一致性状态变换到另一个一致性状态。

所谓一致性,指的是数据处于一种有意义的状态,这种状态是语义上的而不是语法上的。最常见的例子是转帐。例如从帐户A转一笔钱到帐户B上,如果帐户A上的钱减少了,而帐户B上的钱却没有增加,那么我们认为此时数据处于不一致的状态。

隔离性(Isolation)
一个事务的执行不能被其他事务干扰。它要求数据库在执行一个事务时,其它操作无法存取到正在执行事务访问的数据。

比如某件商品库存10件,在一个事务过程中,用户A对该商品下单6件,而另外,用户B也对该商品下单5件,那累加后就超过库存数了,不符合业务要求。所以是,在事务的修改某数据时候,其他的不能修改该数据,但是可以访问该数据,但只能访问到事务开始前的值(不一定,不同的隔离级别看到的值就不一样的)。这样就是两个进行了隔离。

持久性(Durability)
一个事务一旦提交,他对数据库中数据的改变就应该是永久性的。当事务提交之后,数据会持久化到硬盘,修改是永久性的。

3.如何开启事务

 事务分为隐式事务显式事务。

隐式事务

mysql中事务默认是隐式事务,执行insert、update、delete操作的时候,数据库自动开启事务、提交或回滚事务。

是否开启隐式事务是由变量autocommit控制的。

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

--autocommit为ON表示开启了自动提交

显式事务

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

 建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update test set name='sss' where id=7;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

4.隔离级别 

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题。

(1)脏读:一个事务读到另外一个事务没有提交的数据

解释:例如两个并发的事务a和b,其中事务A查完数据库中的一条记录后,事务a继续修改了一条记录,此时事务A并未提交,此时并发事务b读取了事务a修改的记录,这就导致事务b读取到事务a未提交的数据

(2)不可重复读:一个事务先后读取同一条记录,但是两次读取的数据不同

解释:例如两个并发事务a和b,其中事务a读取数据库中的一条记录后,事务b对数据库的这条记录进行修改后,提交事务b,此时事务a继续读取这条记录,发现和上次读取的数据不一样

(3)幻读:一个事务按照条件查询数据,没有对应的数据行,准备插入数据时,发现这行数据存在

解释:例如两个并发事务a和事务b,其中事务a读取了id=1的数据时,发现没有这条记录,然后事务b插入id=1的数据,并且提交了事务b,此时事务a准备插入id=1的数据时发现已经存在这条数据,因为插入数据时报错,显示有这条记录

不可重复读,关注是其他事务修改数据并提交了事务,前后两次读取到的数据不一致的问题;幻读是新插入的行导致出现的问题

为了解决这些问题,就有了“隔离级别”的概念。 

mysql中一共有4中隔离级别,其中可重复读是默认级别

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

 上面4中隔离级别越来越强,会导致数据库的并发性也越来越低。

--查看隔离级别(两条任一条都行,这是查询当前会话的)
show variables like 'transaction_isolation';
select @@transaction_isolation;

--查看全局隔离级别
SELECT @@GLOBAL.TRANSACTION_ISOLATION;

--设置隔离级别
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }


--MySQL的session和global一般使用在终端,用来对配置进行暂时设置,当数据库服务重启就会失效。session和global体现在新的设置生效的范围。
--session:当前会话,也就是当前连接立即生效。
--global:全局,不包含当前连接,之后新获取的连接都会生效。

5.隔离级别的演示

 每个隔离级别可能出现的问题如下 

 读未提交级别

出现脏读

 读已提交级别

解决脏读,出现不可重复读问题。

步骤5更新数据后还未提交,到步骤6查看,数据没有改变,说明读已提交解决了脏读问题。

而步骤6和步骤8查看的数据是不一致的,这个就出现了不可重复读问题。(在同一个事务先后读取同一条记录,但是两次读取的数据不同)。

 可重复读级别

解决不可重复读问题,出现幻读。

解决了不可重复读问题,步骤3,6,8读到的数据都是一致的。在步骤9提交后,步骤10读到的数据就是更新后的数据。

出现幻读。 

 步骤3插入数据(15,15,15)。步骤4查看是显示没有的。步骤5想插入数据,却显示id=15的数据有冲突,说明已有id=15的数据。而之后步骤6更新id=15的数据,却显示成功了。

步骤6查看,却读到id=15这一行,这个就是幻读。幻读仅专指“新插入的行”。

也就是说,幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行

可串行化级别

解决所有问题,但也是性能最差的一个

步骤5中会一直被卡住,等到超时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值