# 1、概述

# 1.1、什么是事务

  • 事务就是将一组SQL语句放在同一批次内去执行。
  • 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行。
  • MySQL事务处理只支持InnoDB和BDB数据表类型。

# 1.2、事务的ACID原则

# 1、原子性(Atomic)

整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执 行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过 一样。

问题1:如何保证原子性

利用Innodbundo log

undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的sql语句,他需要记录你要回滚的相应日志信息。

例如:

(1)当你delete一条数据的时候,就需要记录这条数据的信息,回滚的时候,insert这条旧数据

(2)当你update一条数据的时候,就需要记录之前的旧值,回滚的时候,根据旧值执行update操作

(3)当年insert一条数据的时候,就需要这条记录的主键,回滚的时候,根据主键执行delete操

undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

# 2、一致性(Consist)

一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务 一样操作。其主要特征是保护性和不变性(Preserving an Invariant)。

以转账案例为例,假设有五 个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多 个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之 间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。

# 3、隔离性(Isolated)

隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相 同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系 统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同 一时间仅有一个请求用于同一数据。

注意这里隔离可能会有一些问题:

  • **脏读:**指一个事务读取另外一个事务未提交的数据。
  • **不可重复读:**在一个事务内读取表中的某一行数据,多次读取结果不同.(这个不一定是错误,只是某些场合不对)。
  • **虚读(幻读):**是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

# 4、持久性(Durable)

在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。即使出现宕机也不会丢失。

问题1:Mysql怎么保证持久性的

是利用Innodbredo log

正如之前说的,Mysql是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回磁盘上。如果此时突然宕机,内存中的数据就会丢失。

**问题解决:**事务提交前直接把数据写入磁盘就行了。

**此时还会有问题:**只修改一个页面里的一个字节,就要将整个页面刷入磁盘,太浪费资源了。毕竟一个页面16kb大小,你只改其中一点点东西,就要将16kb的内容刷入磁盘,听着也不合理。

毕竟一个事务里的SQL可能牵涉到多个数据页的修改,而这些数据页可能不是相邻的,也就是属于随机IO。显然操作随机IO,速度会比较慢。

于是,决定采用redo log解决上面的问题。当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo logbinlog内容决定回滚数据还是提交数据。

# 2、事务实现

1、基本语法:

-- 使用set语句来改变自动提交模式
SET autocommit = 0; /*关闭*/
SET autocommit = 1; /*开启*/


-- 注意:
--- 1.MySQL中默认是自动提交
--- 2.使用事务时应先关闭自动提交

-- 开始一个事务,标记事务的起始点
START TRANSACTION

-- 提交一个事务给数据库
COMMIT

-- 将事务回滚,数据回到本次事务的初始状态
ROLLBACK

-- 还原MySQL数据库的自动提交
SET autocommit =1;

-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

2、事务处理步骤:

20220928144246

# 3、练习

/*
A在线买一款价格为500元商品,网上银行转账.
A的银行卡余额为2000,然后给商家B支付500.
商家B一开始的银行卡余额为10000
创建数据库shop和创建表account并插入2条数据
*/

CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;

CREATE TABLE `account` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(32) NOT NULL,
    `cash` DECIMAL(9,2) NOT NULL,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO account (`name`,`cash`)
VALUES('A',2000.00),('B',10000.00)

-- 转账实现
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开始一个事务,标记事务的起始点
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT; -- 提交事务,这时执行完之后,A和B的数据都会发生改变
# rollback;
SET autocommit = 1; -- 恢复自动提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
最近更新: 1/8/2024, 11:36:09 AM
Copyright © - 码上言   |