1、何为事务?
概念:事务执行是一个整体,所有的SQL语句都必须执行成功。如果其中有1条SQL语句出现异常,则所有的SQL语句都要回滚,整个业务执行失败。
解释:实际开发过程中,很多时候都是要多次访问数据库才能完成的。比如转账,张三有1000块,李四也有1000块。老王转账500元给小王。在实际的操作数据库过程中,就分为两次。第一次是张三账户扣500,第二次是李四账户加500。如果在执行的过程中,张三扣了500,但是李四加500的时候出错了。那么第一条语句执行成功,第二条语句失败,那么500块就凭空消失了。事务就是保证业务没有全部执行成功的时候,能够归滚到最初的状态的一种保证机制。
2、基本操作
关键词
- 开启事务–>START TRANSACTION;
- 回滚–>ROLLBACK;
- 提交–>COMMIT;
(新手小TIPS: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
UPDATE account SET balance = balance - 500 WHERE name='张三';
-- 李四账号+500
UPDATE account SET balance = balance + 500 WHERE name='李四';
-- 这样的步骤,正常执行无差错,就是转账成功
-- 未开启事务,异常执行
-- 恢复到各1000元
UPDATE account SET balance = 1000;
-- 张三账号-500
UPDATE account SET balance = balance - 500 WHERE name='张三';
-- 李四账号+500
哈哈哈哈UPDATE account SET balance = balance + 500 WHERE name='李四';
-- 没有事务的情况下,转账失败,但是张三少了500元
-- 手动开启事务,异常执行
-- 恢复到各1000元
UPDATE account SET balance = 1000;
--手动开启事务
START TRANSACTION;
-- 张三账号-500
UPDATE account SET balance = balance - 500 WHERE name='张三';
-- 李四账号+500
哈哈哈哈UPDATE account SET balance = balance + 500 WHERE name='李四';
-- 回滚
ROLLBACK;
-- 转账失败,但是回滚到最初状态,双方资金保护的很好
-- 手动开启事务,正常执行
-- 恢复到各1000元
UPDATE account SET balance = 1000;
--手动开启事务
START TRANSACTION;
-- 张三账号-500
UPDATE account SET balance = balance - 500 WHERE name='张三';
-- 李四账号+500
UPDATE account SET balance = balance + 500 WHERE name='李四';
-- 提交
COMMIT;
-- 执行完毕
(新手小TIPS:MySQL默认每一条DML(增删改)语句都是一个单独的事务,每条语句都会自动开启一个事务,语句执行完毕自动提交事务,MySQL默认开始自动提交事务;Oracle默认不开始自动提交)
3、 回滚点
在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功,可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点
设置回滚点 --> savepoint 名字
回到回滚点 --> rollback to 名字
会上面的操作之后,回滚点应该也会了,就不实例展示了。
4、 事务原理
其实,事务开启之后, 就是把所有的操作都会临时保存到事务日志中, 事务日志只有在得到commit命令才会同步到数据表中,其他任何情况都会清空事务日志(rollback,断开连接)
5、事务四大特性
- 原子性(Atomicity):每个事务都是一个整体,不可再拆分,事务中所有的SQL语句要么都执行成功,要么都失败。
- 一致性(Consistency):事务在执行前数据库的状态与执行后数据库的状态保持一致。如:转账前2个人的总金额是2000,转账后2个人总金额也是2000
- 隔离性(Isolation):事务与事务之间不应该相互影响,执行时保持隔离的状态。
- 持久性(Durability):一旦事务执行成功,对数据库的修改是持久的。就算关机,也是保存下来的。
6、并发访问问题与隔离级别
并发访问问题主要是多个用户同时访问同一个数据造成的,主要是如下问题:
- 脏读 --> 一个事务读取到了另一个事务中尚未提交的数据
- 不可重复读(虚读) --> 一个事务中两次读取的数据内容不一致,要求的是一个事务中多次读取时数据是一致的,这是事务update时引发的问题
- 幻读 --> 一个事务操作数据表中所有的记录,另一个事务添加了一条数据,第一个事务查询不到自己的修改
通过设置隔离级别,就可以解决并发访问问题。我做的这个表,清楚的表达了隔离级别与问题的对应关系
级别 | 隔离级别 | 脏读 | 不可重复读 | 幻读 | 数据库默认级别 |
1 | read uncommitted | 会产生 | 会产生 | 会产生 | / |
2 | read committed | 不会产生 | 会产生 | 会产生 | Oracle和SQL Sever |
3 | repeatable read | 不会产生 | 不会产生 | 会产生 | MySQL |
4 | serializable | 不会产生 | 不会产生 | 不会产生 | / |
隔离级别越高,性能越差,安全性越高
查询隔离级别–>select @@tx_isolation;
-- 查询隔离级别
SELECT @@tx_isolation;
-- 设置隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别字符串;
注意:设置事务隔离级别,需要退出MySQL再重新登录才能看到隔离级别的变化