【MySQL基础篇】事务

事务简介

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或或撤销操作请求,即这些操作要么同时成功,要么同时失败。

典型事例:银行转账操作

假设张三向李四进行转账操作首先第一步我们应该查询张三用户的余额,如果余额充足,则张三用户余额减少,最后李四用户余额增加

事务的步骤分为:1、开启事务2、回滚事务(把临时修改的数据恢复回去,能够保证如果出现异常,全部操作都会回滚,保证数据的完整性和一致性)3、提交事务

默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。

事务操作

· 查看/设置事务提交方式

SELECT @@autocommit;

SET @@autocommit=0;

· 提交事务

COMMIT;

· 回滚事务

ROLLBACK;

sql 复制代码
#事务操作
#数据准备
create table account(
    id int primary key auto_increment comment '主键ID',
    name varchar(10) comment '姓名',
    money int comment '余额'
)comment '账户表';
insert into account values(null,'张三',2000),
                          (null,'李四',2000);
#转账操作
select @@autocommit;
set @@autocommit=0;
select * from account where name='张三';
#2、将张三账户余额减1000
update account set money =money-1000 where name='张三';
程序执行错误
#3、将李四账户余额增加1000
update account set money =money+1000 where name='李四';
#提交事务
commit;
#回滚事务
rollback;
#恢复数据
update account set money=2000 where name='张三'||name='李四';

方式二:不设置事务的提交方式

· 开启事务

START TRANSACTION 或 BEGIN;

· 提交事务

COMMIT;

· 回滚事务

rollback;

sql 复制代码
#方式二:
start transaction ;
set @@autocommit=1;
select * from account where name='张三';
#2、将张三账户余额减1000
update account set money =money-1000 where name='张三';
程序执行错误...
#3、将李四账户余额增加1000
update account set money =money+1000 where name='李四';
#提交事务
commit;
#回滚事务
rollback;

事务四大特性:ACID

· 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。

· 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。

· 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。

· 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

并发事务问题

|-------|-------------------------------------------------------|
| 问题 | 描述 |
| 脏读 | 一个事务读到另一个事务还没有提交的数据 |
| 不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读 |
| 幻读 | 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影" |

事务的隔离级别

|---------------------|----|-------|----|
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
| Read uncommitted | √ | √ | √ |
| Read committed | × | √ | √ |
| Repeatable Read(默认) | × | × | √ |
| Serializable | × | × | × |

注意:从上到下隔离级别越来越高, Serializable隔离级别最高但性能最差;Read uncommitted隔离级别最低(数据安全性最差),但性能最优。

#查询事务隔离级别

SELECT @@TRANSACTION_ISOLATION;

#设置事务隔离级别

SET SESSION \| GLOBAL TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

sql 复制代码
#查看事物的隔离级别
select @@transaction_isolation;
#设置事务隔离级别
set session transaction isolation level read uncommitted;
#改回默认值
set session transaction isolation level repeatable read ;

脏读演示:(两个客户端演示)

sql 复制代码
#第一个客户端
mysql> use test
Database changed
mysql> set session transaction isolation level read uncommitted
    -> ;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  2000 |
|  2 | 李四 |  2000 |
+----+------+-------+
2 rows in set (0.00 sec)

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

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  2000 |
|  2 | 李四 |  2000 |
+----+------+-------+
2 rows in set (0.00 sec)

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  1000 |
|  2 | 李四 |  2000 |
+----+------+-------+
sql 复制代码
#第二个客户端
mysql> use test
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update account set money=money-1000 where name='张三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

不可重复读:(此时隔离级别为Read committed)

sql 复制代码
#第一个客户端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  1000 |
|  2 | 李四 |  2000 |
+----+------+-------+
2 rows in set (0.00 sec)

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  2000 |
|  2 | 李四 |  2000 |
+----+------+-------+
2 rows in set (0.00 sec)
sql 复制代码
#第二个客户端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update account set money=money+1000 where name='张三';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

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

幻读:(此时隔离级别为Repeatable read)

sql 复制代码
#第一个客户端
 start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  2000 |
|  2 | 李四 |  2000 |
+----+------+-------+
2 rows in set (0.00 sec)

mysql> select * from account where id=3;
Empty set (0.00 sec)
 insert into account(id,name,money) values(3,'王小五',2000);
ERROR 1062 (23000): Duplicate entry '3' for key 'account.PRIMARY'
mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | 张三 |  2000 |
|  2 | 李四 |  2000 |
|  3 | 王五 |  2000 |
+----+------+-------+
3 rows in set (0.00 sec)
sql 复制代码
#第二个客户端
 start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account(id,name,money) values(3,'王五',2000);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)
相关推荐
北域码匠3 小时前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
plainGeekDev5 小时前
MVC 写法 → MVVM
android·java·kotlin
恋猫de小郭6 小时前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter
三少爷的鞋7 小时前
“结构化”这个词,本质上就是——把混乱的东西变成有组织、有规则、有边界的东西
android
方白羽1 天前
Android Gradle 缓存与文件目录深度解析
android·gradle·android studio
李白客1 天前
KES新版MySQL兼容能力再升级意味着什么?
mysql·国产数据库
ClouGence1 天前
Oracle 数据同步为什么会出现数据不一致?长事务是常被忽略的原因
数据库·后端·oracle
曲幽1 天前
Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招!
android·termux·nohup·services·wake-lock
plainGeekDev1 天前
单例模式 → object 声明
android·java·kotlin
程序员陆业聪1 天前
读者点单·03|Compose 与传统 View 混用的 12 个真实坑
android