一 事务简介
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一
个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
例如:银行转账
张三 ---(转账1000元)---> 李四
在进行转账的具体逻辑:
a.查询张三的账户余额
b.张三的账户余额-1000
c.李四的账户余额+1000
假如发生异常:
a执行成功,b执行成功,执行c时业务抛出异常
意味着:张三的钱减少了,但是李四的钱并没有增加,这个时候数据就出现问题,
对于这种问题就要用到数据库的事务操作,要么全部执行成功,要么全部执行失败。将[a,b,c]三个事件封装到一个事务中,首先开启事务,如果事务中的每一个步骤都成功完成,那么最终提交任务,一旦有一个步骤无法成功实现,那么就会进行回滚事务,回滚事务会将之前修改的数据全部重置为原来的数据。
MYSQL是具有自动提交事务的功能,也就是说每当我们执行一条SQL语句,MySQL就会自动提交事务。因此我们想要把若干个操作放在一个事务内,我们就要手动的去开启事务,手动的去提交事务,如果出现异常手动的实现事务的回滚。
二 操作演示
准备数据
-- 事务的操作
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);
正常的转账情况
-- 转账操作(张三给李四转账1000)
-- 1.查询张三账户余额
select * from account where name = '张三'-- 2.将张三账户的余额-1000update account set money = money -1000 where name = '张三';-- 3.将李四的账户余额+1000update account set money = money + 1000 where name = '李四';
出现异常的情况
将select中直接添加汉字运行即可出现异常。
运行效果
可以发现张三的账户余额减少,但是李四的账户余额并没有发生变化。因此为了处理这个问题我们就要用到事务。接下来讲如何操作。
▶ 事务操作
-- 查看/设置事务提交方式
select @@autocommit;
set @@autocommit =0;
-- 提交事务
commit;
-- 回滚事务
rollback;
方式一:
这样操作可以实现事务的操作,保证出现异常情况数据不会被修改
方式二:
-- 开启事务
start transaction 或 begin;
-- 提交事务
commit;
-- 回滚事务
ROLLBACK;
三 四大特性
■ 原子性(Atomicity)︰事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
■ 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
■ 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
■ 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
四 并发事务问题
一.脏读
事务A中执行三个操作,假如第一个执行select语句,第二个执行update语句,事务没有执行完成的时候事务是没有提交的,只有事务的三步操作完成以后才会提交,事务A执行第二步以后就会对数据库里面的内容进行更新,而此时事务B要执行的就是一个查询的工作,
那么B事务就会将这个更新了的数据查询到,此时事务A还没有进行完成。一个事务读取到了另一个事务没有执行完成的数据:脏读。
二.不可重复读
事务A先执行一个select操作,B事务进行了一个UPdate操作并进行了提交,然后A事务第三步又执行了一个select操作,而此时读取出的数据和第一次读取出的数据不同。
三.幻读
事务A,第一步select操作发现没有数据,事务B进行insert操作,并提交到了数据库。接下来,事务A执行第二部insert操作,此时不能插入成功(id是主键)。
五 事务的隔离级别
▶ 基本语法
-- 查看事务隔离级别
select @@transaction_isolation;
-- 设置事务隔离级别
SET [SESSION|GLOBAL ] TRANSACTION IsOLATION LEVEL { READ UNCOMMITTED |READ COMMiTTED | REPEATABLE READ |SERIALIZABLE}
这里模拟两个事务,我们可以开两个窗口模拟实现,这里用命令行模式。
1.READ UNCOMMITTED
模拟出现脏读。事务A读取到了事务B还没有提交的数据。
2.READ COMMITTED
READ COMMITTED 解决了脏读,但是出现了不可重复读
3.REPEATABLE READ
解决了不可重复读,但是存在幻读问题。
事务A先查询了一次ID为3的记录发现并没有,此时事务B对account修改插入了一条ID为三的数据并进行了提交,然后事务A由于没有查询到ID为3的记录,将执行一次插入ID为3的操作,可时,出现了主键约束不能重复的问题,表示已经有了ID为3的记录,可时接下来再执行查询语句,发现ID为3的记录仍然没有,这就是出现的幻读。如下图所示:
4.SERIALIZABLE
SERIALIZABLE可以规避所有的并发事务问题,但是它的性能最差。事务A还在执行中时,事务B对表进行插入数据明显发生阻塞现象,只有事务A提交了事务B才可以继续执行,很好的避免了幻读的问题,如下图所示:
注意:
事务的隔离级别越高,数据越安全,但是性能越来越低。