一、什么是数据库事务
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典的例子就是转账:
操作: 张三和李四各自的账号都是1000元;张三向李四转账100元
组成单元: 张三钱-100, ls钱+100
操作成功: 张三钱900,ls钱1100
操作失败: 张三钱1000,ls钱1000
不可能发生: 张三钱900,ls钱1000; zs钱1000,ls钱1100
二、MySQL进行事务管理
1.自动事务(MySQL默认的)
-- 场景: zs向ls转账100元
-- zs钱-100 ls钱+100
-- 自动事务管理: MySQL默认就是自动事务管理(自动开启事务,自动提交事务),一条sql语句就是一个事务
update account set money = money - 100 where name = 'zs'; 5 -- 异常
update account set money = money + 100 where name = 'ls';
2.手动开启一个事务
方法一:
start transaction;开启事务
commit;提交
rollback;回滚
-- 没有异常
start transaction; -- 开启事务
update account set money = money - 100 where name = 'zs'; -- zs钱-100
-- 没有异常
update account set money = money + 100 where name = 'ls'; -- ls钱 +100
commit; -- 提交事务
-- 有异常
start transaction; -- 开启事务
update account set money = money - 100 where name = 'zs'; -- zs钱-100
-- 有异常
update account set money = money + 100 where name = 'ls'; -- ls钱 +100
rollback; -- 回滚事务
方法二:
设置MySQL中的自动提交的参数
查看MYSQL中事务是否自动提交
show variables like '%commit%';
设置自动提交的参数为OFF
set autocommit = 0;-- 0:OFF 1:ON
三、回滚点
1. 什么是回滚点
在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功,可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之为回滚点。
2. 回滚点操作语句
回滚点的操作语句 | 语句 |
设置回滚点 | savepoint名字 |
回到回滚点 | rollback to 名字 |
3、具体操作
1) 将数据还原到1000
2) 开启事务
3) 让张三账号减3次钱
4) 设置回滚点:savepoint three_times;
5) 让张三账号减4次钱
6) 回到回滚点:rollback to three_times;
总结:设置回滚点可以让我们在失败的时候回到回滚点,而不是回到事务开启的时候。
start transaction;
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
-- 以上sql语句没有问题
savepoint abc;
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
-- 出现异常,回滚到abc回滚点位置
rollback to abc;
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
update account set money = money - 100 where name = 'zs'; -- zs账户-100
commit;
4、应用场景
插入大量的数据的时候. 1亿条数据 需要插入很久. 要求: 1亿条数据是一个整体,要么全部插入成功的 要么都不插入成功.
注意:
1、建议手动开启事务, 用一次 就开启一次
2、开启事务之后, 要么commit, 要么rollback
3、一旦commit或者rollback, 当前的事务就结束了
4、回滚到指定的回滚点, 但是这个时候事务没有结束的
四、事务管理的四大特性
-
原子性(Atomicity):事务被视为一个不可分割的原子操作,要么全部执行成功,要么全部失败回滚,不会存在部分执行成功部分失败的情况。
-
一致性(Consistency):事务执行前后,数据库状态应保持一致。即事务执行完毕后,所有数据应符合预设的规则和约束条件。
-
隔离性(Isolation):多个事务并发执行时,每个事务对其他事务的操作应该互不干扰,各自独立运作,避免数据交叉影响。
-
持久性(Durability):一旦事务提交成功,其所做的修改就应该永久保存在数据库中,即使系统崩溃或断电,也不应该丢失数据。
五、事务隔离级别以及对应的问题
1.四个隔离级别以及对应的问题
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交 | 允许 | 允许 | 允许 |
读已提交 | 禁止 | 允许 | 允许 |
可重复度 | 禁止 | 禁止 | 可能会 |
顺序读 | 禁止 | 禁止 | 禁止 |
SQL 标准定义了四个隔离级别:
1、READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
2、READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
3、REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
4、SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
注意:
1、 这里需要注意的是:Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别
2、事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。
3、因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。