数据库事务及其原理
一.什么是事务
事务简单说将一串操作看成一个整体,只有当这串操作全部执行成功的时候才成功,只有有一个操作出错就失败,回滚到操作开始之前。这一串操作就是事务。
比如张三给李四转账100块这件事有三个步骤,
查询张三余额,张三自己账户先扣一百块,然后李四账户获得一百块。
如果张三扣款成功,但李四获得一百块失败,那么不是转账失败,凭空损失了100块?或者张三扣款失败,但李四获得一百块成功,那张三不是凭空赚了100块?
然后我们将这两个事情打包,规定有一件事情做错就代表失败并回滚到最初的状态,就保证了数据的一致性,解决了上面的问题。
注意: 默认MySQL的事务是自动提交的,也就是说,当执行完一条DML语句时,MySQL会立即隐 式的提交事务。简单说其实一条DML也有事务。
二.如何添加事务
除了上面的默认单条语句会隐式加上事务,我们也可以显示为一系列SQL语句加上事务。
-- 开启事务
start transaction
-- 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):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
上述就是事务的四大特性,简称ACID。
四.事务并发问题
(1)丢失修改 -- 两个或多个事务同时读取同一数据并进行更新时,其中一个事务的更新结果被另一个事务的更新覆盖,导致前一个事务的修改丢失。
(2)赃读 -- 一个事务读取了另一个事务尚未提交的修改数据,而后者可能会回滚导致数据不一致。
脏读会让事务读取到不正确的中间状态数据。
(3)不可重复读 -- 一个事务内多次读取同一数据时,由于其他事务的修改或提交,导致每次读取的结果不同。
(4)幻读:一个事务先后查询同一条记录,刚开始没有查询到对应的数据行,但是另一个事务在这过程中插入数据,然后再次查询,又发现这行数据已经存在,好像出现了 "幻影"。
总结
丢失修改就是类似经典竞态问题,多个线程修改导致最终修改后的数据不一致
脏读就是因为rollback造成的前后读取数据不一致
不可重复度是因为update造成的前后读取数据不一致
幻读是因为insert和delete造成的前后读取数据不一致
丢失修改是修改后的数据不正确,其他是因为各种因为其他线程各种原因的修改导致的前后读取的数据不正确。
五.事务隔离级别
【1】为了解决并发事务所引发的问题,在数据库中引入了事务隔离级别。主要有以下几种:
SQL 标准定义了四个隔离级别:
READ-UNCOMMITTED(读取未提交) :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
READ-COMMITTED(读取已提交) :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
REPEATABLE-READ(可重复读) :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
SERIALIZABLE(可串行化) :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
怎么记呢?
读取未提交就是防止丢失修改
读取已提交就是进一步防止rollback,从而防止脏读
可重复读就是进一步防止update,从而防止不可重复读
可串行化就是进一步防止insert和delete,从而防止幻读
【2】在mysql中可以使用下面的查看和设置事务隔离级别。
SELECT @@TRANSACTION_ISOLATION; # 查看事务隔离级别
SELECT @@transaction_isolation; # mysql8.0修改了上面的命令语法
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }#设置事务隔离级别
在Mysql中默认是可重复读,其他数据库很多都默认是读取已提交。
【3】但是需要注意,事务隔离级别越高,数据越安全,但是性能越低。
六.原理
TODO