红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. 专栏
  3. MySQL学习笔记
  4. 正文

MySQL 从入门到精通 5:事务

2025年8月2日 81点热度 0人点赞 0条评论

案例

先看一个案例,假设有一个银行账户表:

create table account(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    money int comment '余额'
) comment '账户表';
insert into account(id, name, money) VALUES (null,'张三',2000),(null,'李四',2000);

张三和李四的初始资金都是2000,现在要将张三账户中1000转给李四,要执行下面的操作:

select * from account where name='张三';
update account set money=money-1000 where name='张三';
update account set money=money+1000 where name='李四';

具体的过程为:

  1. 查询张三账户的余额是否足够

  2. 从张三账户中扣减1000

  3. 给李四账户增加1000

在一般情况下这样做没问题,但如果某条 SQL 执行时出错,就可能导致数据不一致的情况出现,比如:

select * from account where name='张三';
update account set money=money-1000 where name='张三';
-- 模拟SQL 执行出错
执行出错
update account set money=money+1000 where name='李四';

执行的结果可能是张三的账户被扣除金额,但李四的账户并没有增加金额。

这里执行的结果取决于 MySQL 客户端,新版本的 DataGrip 会识别语法错误的 SQL 语句,跳过该语句的执行。

如果要确保一组 SQL 执行结果的一致性,就需要使用事务。

控制事务

MySQL 默认启用事务自动提交,即将每一条 SQL 看做一个事务,SQL 执行后立即进行提交。这个行为由会话变量@@autocommit决定:

select @@autocommit;

默认情况下返回结果是 1,表示开启事务的自动提交。

如果要关闭,可以:

set @@autocommit=0;

当前会话的自动提交会被关闭,现在所有 SQL 执行后要让数据库发生改变,都需要手动提交事务,比如:

update account set money=money-1000 where name='张三';
commit ;

除了这种方式外,还可以手动开启和提交事务:

start transaction ;
select * from account where name='张三';
update account set money=money-1000 where name='张三';
update account set money=money+1000 where name='李四';
commit ;

通过以下命令控制事务:

  • start transaction/begin,手动开启事务

  • commit,提交事务

  • rollback,回滚事务

四大特性

事务具有四大特性:

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

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

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

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

并发事务

当多个并发的事务执行时,可能存在下面的问题:

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

关于这三个问题的详细说明,可以观看视频。

隔离级别

MySQL 提供不同级别的隔离机制,解决事务并发可能引发的问题:

隔离级别 脏读 不可重复读 幻读
Read uncommitted ✔ ✔ ✔
Read committed ✖ ✔ ✔
Repeatable Read(默认) ✖ ✖ ✔
Serializable ✖ ✖ ✖

从上到下隔离级别依次提高,可以避免更多的并发问题,但性能也逐步降低。

可以通过变量查看当前的隔离级别:

select @@transaction_isolation;

默认情况下是REPEATABLE-READ。

可以通过以下命令修改事务隔离级别:

set session transaction isolation level read uncommitted ;

set session ...只会修改当前会话的隔离级别,如果要修改全局,需要使用set global ...。

关于不同事务隔离级别解决不同事务并发问题的演示,可以看这个视频。

参考资料

  • 黑马程序员 MySQL数据库入门到精通

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: MySQL 事务
最后更新:2025年8月2日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号