From 23720cdf110a78fdc6d08e2999b4bb422ab2228f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E6=99=97=E5=B8=8C?= <2095000342@qq.com> Date: Thu, 17 Oct 2024 15:41:01 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BD=9C=E4=B8=9A=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 林晗希 <2095000342@qq.com> --- .../20241017 \344\272\213\345\212\241.md" | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 "\346\236\227\346\231\227\345\270\214/20241017 \344\272\213\345\212\241.md" diff --git "a/\346\236\227\346\231\227\345\270\214/20241017 \344\272\213\345\212\241.md" "b/\346\236\227\346\231\227\345\270\214/20241017 \344\272\213\345\212\241.md" new file mode 100644 index 0000000..9950e9b --- /dev/null +++ "b/\346\236\227\346\231\227\345\270\214/20241017 \344\272\213\345\212\241.md" @@ -0,0 +1,225 @@ +# MySQL事务管理 + +## 一、事务概念 + +##### 事务就是由一条或者多条 SQL 命令组成的逻辑工作单元。作为一个整体,这些SOL命令相互依赖、不可分割,只要一条SQL 命令执行失败,前面已经成功执行的 SQL 命令就会撤销,回退到事务开始前的状态。 + +##### 也就是说,只有事务的全部命令都成功执行,该事务才算成功。 + +### 支持事务的数据库必须拥有以下4个特性 + +##### (1)原子性(Atomicity):事务中多条SQL语句作为一个整体被执行,事务中的全部操作要么全部成功执行,要么都不执行。 + +##### (2)一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态,要么同时成功要么同时失败。 + +##### (3)隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。 + +##### (4)持久性(Durability):已提交的事务对数据库的修改应该永久保存在数据库中。 + +##### 事务就是一组SQL命令的批处理,但这个批处理是一个原子(整体),不能分割,要么都执行,要么都不执行。 + +## 二、MySQL事务处理分类 + +### 1、系统定义事务 + +系统定义事务是指默认情况下,MySQL 将每条单独的命令都看作一个事务,每条命令行成功都会自动提交,执行失败就自动回滚。 + +**mysql事务默认情况下是自动提交的,就是执行任意一条DML语句则提交一次** + +### 2、用户定义事务 + +用户定义事务是指由用户自己来定义事务的开始、结束、回滚和提交等状态的事务。 + +用户定义的事务可以包含多条命令,但用户必须显式或隐式地关闭自动提交。 + + + +```sql +set @@autocommit=0; -- 将系统变量中的自动提交改为禁用 +``` + +(1)START TRANSACTION 命今用于显式地开启事务。 +(2)COMMIT 命令用于提交事务,就是将事务开始以来的所有数据修改保存到磁盘中,也标志一个事务的结束。 + +> 需要注意的是,MySQL不允许使用嵌套的事务,不能在一个事务中包含另一个事务。 + +(3) ROLLBACK 命令用于回滚事务所做的修改,并结束当前这个事务。 + +(4)除了撤销整个事务,用户还可以使用 ` ROLLBACK TO [保存点名称]`命令将事务回滚到某个保存点。但这需要事先使用 SAVEPOINT命令设置保存点。SAVEPOINT 命令的语法格式如下: + +```sql +SAVEPOINT 保存点名字; +-- 例如 +savepoint s1;-- s1**即为保存点的名字** +``` + +要将事物回滚到` s1 `这个保存点的命令如下。 + +```sql +ROLLBACK to s1; +``` + +##### 相关演示: + +1. ##### **mysql中的事务是支持自动提交的,只要执行一条DML语句,则提交一次**,**发现回滚回不去了,说明mysql事务默认情况下是自动提交的)** + +2. ##### **使用start transaction关闭自动提交机制** + +3. ##### **(rollback后事务已经结束,从结果上发现rollback后表数据还原了;如果还想启动一个新事务,应该再次start transaction)** + +4. ##### **commit (提交),commit后磁盘中的数据就已经改变,如果再rollback无效)** + +5. ##### **rollback和commit都会结束事务,如果还想启动一个新事务,应该再次start transaction + +## 三、事务隔离级别 + +第一级别:读未提交(Read Uncommitted), + +- 表现形式:A事务还没有提交,B事务可以读取到A事务未提交的数据。 + +- 存在问题:读未提交存在脏读(Dirty Read)现象-->表示读到了脏的数据。 + +- 脏读是指在并发执行的两个事务中,一个事务读到了另一个事务尚未提交的数据。这个数据可能会被回滚【不存在】。 + 第二级别:读已提交(Read Committed), A事务提交之后的数据,B事务可以读取到。这种级别隔离解决了前一种的脏读现 + +- 读已提交数据存在的问题是:不可重复读。 + +- 不可重复读是指在同一个事务中,由于其他事务的干扰,导致同一查询语句返回的结果不同,即A事务提交前后,B事务前后查询的结果不一致。 + +第三级别:可重复读(Reapeatable Read),重复多次读取的数据都是和第一次一样。 + +- 这种隔离级别解决了:不可重复读问题。 +- 这种隔离存在的问题:可能读取到的数据是幻象,即不真实的数据 。 + +第四级别:序列化读/串行化读(serializable), 排队机制,解决了所有问题 + +- 效率底。需要事务排队。 +- 串行化是最高的隔离级别,它强制事务串行执行,避免了脏读、不可重复读和幻读等问题。 +- 在该级别下,MySQL会对所有读取的数据行都加共享锁或排他锁,直到事务结束。 +- 由于串行化对性能的影响比较大,所以一般情况下不建议使用。只有在确实需要完全隔离、对并发度要求不高的业务场景下才使用。 + +Sql Server , Oracle 默认隔离级别是不可重复读,MySQL默认隔离级别可重复读 + +### 演示隔离级别 + +```sql +-- 查询当前全局事务隔离级别 +SELECT @@global.transaction_isolation; +-- 查询当前会话的事务隔离级别 +SELECT @@session.transaction_isolation; + +-- 设置全局隔离级别 +set global transaction isolation level read uncommitted; -- (这里设置的是第一级别读未提交(read uncommitted)** +# 注意修改过级别要新开会话(连接)才会生效。 + +-- 查询事务锁 +SELECT * FROM information_schema.INNODB_TRX; +``` + +#### **一、演示read uncommitted** + +```sql +set global transaction isolation level read uncommitted; +``` + + + +#### **二、演示read committed** + +```sql +set global transaction isolation level read committed; +``` + + + +#### **三、演示repeatable read** + +```sql +set global transaction isolation level repeatable read; +``` + + + +#### 四、演示 serializable + +```sql +set global transaction isolation level serializable; +``` + + + +| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 | +| ---------------------- | --- | ----- | --- | +| 读未提交(read-uncommitted) | 是 | 是 | 是 | +| 读已提交(read-committed) | 否 | 是 | 是 | +| 可重复读(repeatable-read) | 否 | 否 | 是 | +| 可串行化(serializable) | 否 | 否 | 否 | + + + +# 练习与作业 + +```sql +## 练习题: +-- 1、手动关闭系统全局的全动提交。查询表内容,新增一个自己的帐号,和金额,最后回滚。再查询表内容; +SET @@autocommit=0; +INSERT INTO bank VALUES (3,'王五',300); +ROLLBACK; +SELECT * FROM bank; +-- 2、用 START TRANSACTION 开启事务,查询表内容,把李四的金额改成5000,回滚事务,再查询表内容; +START TRANSACTION; +SELECT * FROM bank; +UPDATE bank SET money=5000 WHERE username='李四'; +ROLLBACK; +SELECT * FROM bank; +-- 3、用 START TRANSACTION 开启事务,查询表内容,把李四的金额改成5000,提交事务,再查询表内容; +START TRANSACTION; +SELECT * FROM bank; +UPDATE bank SET money=5000 WHERE username='李四'; +COMMIT; +SELECT * FROM bank; +-- 4、用 START TRANSACTION 开启事务,查询表内容,把张三的金额改成666,设置保存点s1,用自己姓名添加个新账户,金额888888,设置保存s2,回滚到s1保存点,再查询表内容; +START TRANSACTION; +SELECT * FROM bank; +UPDATE bank SET money=666 WHERE username='张三'; +SAVEPOINT s1; +INSERT INTO bank VALUES (3,'王五',888888); +SAVEPOINT s2; +ROLLBACK to s1; +SELECT * FROM bank; +-- 5、[作业]创建一个实现银行转账业务的存储过程transfer(),传入合适的参数如转出账户编号,转入账户编号,转账金额,返回是否转账成功。 +-- 提醒.要考虑转出金额不足的情况 +DELIMITER / +CREATE PROCEDURE transfer( + IN from_id INT, + IN to_id INT, + IN amount INT +) +BEGIN + DECLARE current_balance INT; + -- 开启事务 + START TRANSACTION; + -- 查询转出账户的余额 + SELECT money INTO current_balance FROM bank WHERE id = from_id; + -- 判断转出账户余额是否足够 + IF current_balance >= amount THEN + -- 从转出账户扣除金额 + UPDATE bank SET money = money - amount WHERE id = from_id; + -- 向转入账户增加金额 + UPDATE bank SET money = money + amount WHERE id = to_id; + -- 提交事务 + COMMIT; + SELECT '转账成功' AS result; + ELSE + -- 回滚事务 + ROLLBACK; + SELECT '转账失败,余额不足' AS result; + END IF; +END / +DELIMITER ; + + + +``` + + -- Gitee