一、事务的基本介绍
概念:一个包含多个步骤的操作,被事务管理,要么同时成功,要么同时失败。
基本操作:
①开启事务:start transaction;
②回滚:rollback;
③提交:commit;
-- 开启事务
start transaction;
-- 执行事务中的操作
update scm_sales_order set order_people_num=3 where id='704cb0dc-f12b-4e54-b4d1-fcd3490dd4a6';
update scm_sales_order set order_people=1 where id='704cb0dc-f12b-4e54-b4d1-fcd3490dd4a6';
-- 如果事务成功则提交
COMMIT;
-- 如果事务操作有一步失败则回滚到开启事务语句前状态
ROLLBACK;
事务的提交特别注意事项:
①Mysql中事务是默认自动提交的,即@@autocommit=1;
②当使用start transaction命令时,则需要手动提交,即执行commit命令;
查询提交设置的语句:
①select @@autocommit; -- 1:自动提交事务;0:手动提交事务
②set @@autocommit=0; -- 设置事务提交方式语句
二、事务的四大特征
原子性:事务是不可分割的最小单位,要么同时成功,要么同时失败;
持久性:一旦事务提交或者回滚后,数据库就会发生持久性的数据变化;
隔离性:多个事务之间相互独立;
一致性:事务操作前后,数据总量不变;
三、事务的隔离级别
概念:多个事务之间相互隔离,相互独立,如果多个事务操作到同一批数据,可能会出现问题,mysql中可以通过设置事务的隔离级别来解决这些出现的问题。
可能会出现的问题主要有以下:
①脏读:一个事务中的操作读取到其他事务没有提交的数据;
-- 前提条件:打开两个查询窗口,查询窗口1,此时数据库的隔离级别为read uncommited:读未提交
-- 步骤1:窗口1开启事务
start transaction;
-- 步骤2:打开查询窗口2,窗口2开启事务
start transaction;
-- 步骤3:去窗口1中执行的操作,但是不提交事务,原user表大鸭梨同学的年龄为10
update user set age=age+20 where name='大鸭梨';
-- 步骤4:去窗口2查询user表,发现查询结果为30
select age from user where name='大鸭梨';
-- 结论:在窗口2中查询到了窗口1事务中sql的未提交内容,出现了脏读现象;
-- 解决办法:将本实验前提条件修改为使用隔离级别read committed,则相同的实验步骤下,步骤4读取到的内容为10,可以解决脏读问题。
②不可重复读:一个事务中两次读取到的数据不一样;
-- 前提条件:打开两个查询窗口,查询窗口1,此时数据库的隔离级别为read commited:读已提交
-- 步骤1:窗口1开启事务
start transaction;
-- 步骤2:打开查询窗口2,窗口2开启事务
start transaction;
-- 步骤3:去窗口1中执行的操作,但是不提交事务,原user表大鸭梨同学的年龄为10
update user set age=age+20 where name='大鸭梨';
-- 步骤4:去窗口2查询user表,发现查询结果为10
select age from user where name='大鸭梨';
-- 步骤5:去窗口1执行提交事务
commit;
-- 步骤6:去窗口2查询user表,发现查询结果变更为30
select age from user where name='大鸭梨';
-- 结论:对比步骤4和步骤6的查询结果,可以知道对于窗口2事务,2次读取到的数据结果不一致,则发生了不可重复读取(虚读)问题;
-- 解决方法:相同实验步骤下,将前提条件修改为repeatable read,则步骤6中查询结果和步骤4中查询结果保持一致为10,则解决了虚读问题。当窗口2中的事务commit或者rollback后,再次查询才会查询到变更后的结果为30;
③幻读:一个事务操作全表的数据(DML),另外一个事务新增了一条数据,则第一个事务读取不到新增的记录;
mysql无法演示。
事务的隔离级别:
①read uncommited:读未提交, 可能出现问题:脏读、不可重复读、幻读;
②read committed:读已提交,可能出现问题:不可重复读、幻读;
③repeatable read(mysql默认):可重复读,可能出现问题:幻读;
④serializable:串行化,可解决所有问题;
-- 前提条件:打开两个查询窗口,查询窗口1,此时数据库的隔离级别为serializable:锁
-- 步骤1:窗口1开启事务
start transaction;
-- 步骤2:打开查询窗口2,窗口2开启事务
start transaction;
-- 步骤3:去窗口1中执行的操作,但是不提交事务,原user表大鸭梨同学的年龄为10
update user set age=age+20 where name='大鸭梨';
-- 步骤4:去窗口2查询user表,查询等待中没有结果
select age from user where name='大鸭梨';
-- 步骤5:去窗口1执行提交事务
commit;
-- 步骤6:去窗口2查看sql查询情况,查询出结果为30
-- 结论:窗口1中的事务执行时,进行了锁表,导致窗口2中事务无法查询user表,当窗口1事务执行完成后,窗口2事务才开始执行。
操作事务隔离级别设置语句如下:
-- 查询隔离级别命令
select @@tx_isolation;
-- 更改事务隔离级别命令
set global transaction isolation level READ COMMITTED;