前言
本篇文章主要介绍的是事务相关概念,结合MySQL进行分析。
事务的概念
事务是用户定义的一个数据库操作序列,是同一情况下下进行的多次对数据库的增删改的行为的集合。可以理解为在同一个流程中多次对数据库进行增删改等操作,我们可以称这些操作是在同一事务中。
事务的应用场景说明
在实际的业务开发中,有些业务操作要多次访问数据库。一个业务要发送多条 SQL 语句给数据库执行。需要将多次访问数据库的操作视为一个整体来执行,要么所有的 SQL 语句全部执行成功。如果其中有一条 SQL 语句失败,就进行事务的回滚,所有的 SQL 语句全部执行失败。
有一个最经典的转账的例子,张三给李四转账,张三账号减钱,李四账号加钱,加钱减钱是在同一事务中。
-- 创建数据表
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('张三', 1000), ('李四', 1000);
模拟张三给李四转 500 元钱,一个转账的业务操作最少要执行下面的 2 条语句:
- 张三账号-500
- 李四账号+500
-- 1. 张三账号-500
UPDATE account SET balance = balance - 500 WHERE id=1;
-- 2. 李四账号+500
UPDATE account SET balance = balance + 500 WHERE id=2;
假设当张三账号上-500 元,服务器崩溃了。李四的账号并没有+500 元,数据就出现问题了,平白无故少了500元。我们需要保证其中一条 SQL 语句出现问题,整个转账就算失败。只有两条 SQL都成功了转账才算成功。这个时候就需要用到事务。
MySql提交事务
MYSQL 中可以有两种方式进行事务的操作:
1.手动提交事务 2.自动提交事务
1.MySQL可以使用SQL语句实现手动提交事务
功能 | SQL语句 |
---|---|
开启事务 | start transaction; |
提交事务 | commit; |
回滚事务 | rollback; |
手动提交事务的步骤:
执行成功的情况:开启事务 -> 执行 SQL 语句 -> 成功 -> 提交事务
执行失败的情况:开启事务 -> 执行 SQL 语句 -> 失败 -> 回滚事务
也就是说执行start transaction语句后,执行SQL语句,不会马上生效,而是需要执行commit语句才会生效,执行rollback语句则会取消这一事务内执行过的SQL语句,看起来就好像一个网页中确定或者取消的操作弹框。
2.mysql中是默认自动提交事务的,也就是说执行一条SQL语句后就会自动提交,立即生效。
mysql默认自动提交事务是可以修改的,只需要执行SQL语句set autocommit = 0;
将事务提交方式恢复为自动提交set autocommit = 1;
这样就不用执行start transaction
手动开启事务了。
事务原理
事务开启之后, 所有的操作都会临时保存到事务日志中, 事务日志只有在得到 commit 命令才会同步到数据表中,其他任何情况都会清空事务日志(rollback,断开连接等情况)。
原理图
步骤:
1 创建连接时创建此用户临时日志文件
2 开启事务以后,所有的操作都会先写入到临时日志文件中
3 所有的查询操作从表中查询,但会经过日志文件加工后才返回
4 如果事务提交则将日志文件中的数据写到表中,否则清空日志文件。
回滚点
在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功,可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点。
回滚点操作语句 | SQL语句 |
---|---|
设置回滚点 | savepoint 回滚点名字; |
回滚到回滚点 | rollback to 回滚点名字; |
总结:设置回滚点可以让我们在失败的时候回到设置的某一回滚点,而不是回到事务开启的时候。
事务的四大特性(ACID)
事务特性 | 含义 |
---|---|
原子性(Atomicity) | 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 |
一致性(Consistency) | 事务前后数据的完整性必须保持一致 |
隔离性(Isolation) | 是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离,不能相互影响。 |
持久性(Durability) | 指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响 |
事务的隔离级别
事务在操作时的理想状态:多个事务之间互不影响,如果隔离级别设置不当就可能引发并发访问问题。这些并发问题都是由于不同事务直接交叉了,没有完全隔离开来。
并发访问的问题 | 含义 |
---|---|
脏读 | 一个事务读取到了另一个事务中尚未提交的数据,比如一个事务增加一条数据,但是还没有提交,此时另一个事务读到并使用了这条未提交的数据,这条数据就是脏数据,并不是真实的;因为如果增加这条数据的事务回滚了,那么这条数据就不存在了,但是又被另一个事务读取使用了,就会出问题。删除和更新操作也是一样的 |
不可重复读 | 一个事务中两次读取的数据内容不一致,要求的是一个事务中多次读取时数据是一致的,这是事务 update 时引发的问题 。比如事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。 |
幻读 | 一个事务中两次读取的数据的数量不一致,要求在一个事务多次读取的数据的数量是一致的,这是 insert 或 delete 时引发的问题;比如事务A事先读取了数据共100条,事务B紧接着删除或者增加两条数据并提交事务,而事务A再次统计数据时发现数据量不是100条了。 |
脏读这种情况是存在的,一个事务未提交的数据,另一个事务是能读到的,只不过在MySQL中默认隔离级别为第二级,屏蔽了这种情况。可以手动设置为读未提交,测试能读到没有提交的数据。
MySQL数据库有四种隔离级别:上面的级别最低,下面的级别最高。 “是”表示会出现这种问题, “否”表示不
会出现这种问题。
级别 | 名称 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认隔离级别 |
---|---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | 是 | 是 | 是 | |
2 | 读已提交 | read committed | 否 | 是 | 是 | Oracle 和 SQL Server |
3 | 可重复读 | repeatable read | 否 | 否 | 是 | MySQL |
4 | 串行化 | serializable | 否 | 否 | 否 |
设置事务隔离级别,需要退出 MSQL 再进入 MYSQL 才能看到隔离级别的变化
CSDN:https://blog.csdn.net/qq_27682773
简书:https://www.jianshu.com/u/e99381e6886e
博客园:https://www.cnblogs.com/lixianguo