MySQL数据库——MySQL事务

一、概念

完成一个事情需要的一系列步骤(操作),这些操作要么同时成功,要么同时失败

二、事务的基本操作

张三和李四账户上各有1000元,现在张三向李四转500元

-- 1 创建account表
create table tb_account(
id int(11) auto_increment,
user_name varchar(30) not null,
account_blance  int(11) not null, -- 账户余额
primary key (id)    
)ENGINE=INNODB,default charset =UTF8;

-- 2 插入数据
insert into tb_account(user_name,account_blance)
values('ZS',1000),('LS',1000);

-- 3 执行张三向李四转账500
-- ZS账户-500,LS账户+500
-- 下面两个update语句要么同时执行成功要么同时执行失败
-- 执行下列SQL语句会出现问题:张三的钱减少了,李四的钱没有加上。因为此时的两个update语句并没有使用事务来托管
update tb_account set account_blance=account_blance-500 where id=1;
-- 银行转帐异常情况:如机机房停电
update tb_account set account_blance=account_blance+500 where id=2;

三、事务的四大特征

原子性:事务每一步都是不可再分

一致性:张三和李四账户一共2000块钱,不管转账多少次总金额不变

持久性:当一个事务执行成功(完毕),数据会持久化到磁盘的数据文件中。例如转账成功:张三余额变为500,李四余额变为1500.

隔离性:A事务和B事务同时操作一份数据,相互之间不影响。

四、事务的提交方式、

1)自动提交

不需要写commit;就会自动将DML语句持久化提交

2)手动提交

-- 查询结果为1表示自动提交,0表示手动提交

select @@autocommit;

-- 修改提交方式(自动提交修改为手动提交)

set @@autocommit = 0 ;

五、事务的基本操作

1 开启事务

start transaction;

2 提交事务

commit;

3 回滚事务

rollback;

注意:一旦使用start transaction;开启事务那么自动提交将失效

  如果所有操作都正常执行使用commit;提交事务

  当发生异常情况回滚事务,数据(此时为tb_account表)通常回滚到开启事务之前的状态

六、转账操作

-- 1 开启事务
start transaction;
-- 2 执行SQL语句
update tb_account set account_blance=account_blance-500 where id=1;
 手机转账异常情况:转账过程中手机没电了
update tb_account set account_blance=account_blance+500 where id=2;
-- 3 如果SQL语句全部执行成功就提交事务,如果其中任何一步执行失败,立刻回滚事务
-- 此时第一个update执行成功,第二个update语句执行失败了,并没有提交事务,查询结果如下:
select * from tb_account;
/*
+----+-----------+----------------+
| id | user_name | account_blance |
+----+-----------+----------------+
|  1 | ZS        |            500 |
|  2 | LS        |           1000 |
+----+-----------+----------------+
*/
-- 问题:张三账户的余额减少了,李四账户余额没有增加。这就是脏数据
-- 此时需要将脏数据回滚到开启事务之前
rollback;
-- 回滚完毕再次查询
select * from tb_account;
-- 此时事务回滚到开启之前的状态
/*
+----+-----------+----------------+
| id | user_name | account_blance |
+----+-----------+----------------+
|  1 | ZS        |           1000 |
|  2 | LS        |           1000 |
+----+-----------+----------------+
*/
-- 一个事务一旦开启了,在没有执行commit;或者rollback;之前事务不会结束
-- 相关面试题:工作中有没有用到事务?请解释事务的概念?不使用事务会发生什么问题?使用事务能够解决什么问题?解释事务的四大特征[隔离级别]?

七、事务隔离级别

事务隔离级别

脏读

不可重复读

幻读

读未提交(read-uncommitted)

读已提交(read-committed)

可重复读(repeatable-read)

串行化(serializable)

 查询隔离级别

select @@tx_isolation

工作中:1和4都不用,只会在2和3之间切换

MySQL默认的事务隔离级别为3,Oracle默认隔离界别默认为2

SELECT @@global.tx_isolation; //查询全局事务
SELECT @@session.tx_isolation; //查询当前会话事务

set transaction isolation level 级别

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
//测试可以不用设置全局事务
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
//(这个可以不用设,只设置上面一行就可以了进行测试了)

脏读:

一个事务(A)读取到另一个事务(B)没有提交的数据(破坏了隔离性).

  例如:事务A开启事务做转账,DML语句执行成功但是没有commit;事务B在另一个窗口开启了,执行Select语句读取tb_account数据,读取到的结果是事务A没有提交的数据。

不可重复读:

同一个事务中多次读取到的数据不一致(破坏了一致性,update和delete)

  例如:事务A开启事务做转账,DML语句执行成功但是没有commit;;事务B在另一个窗口开启了,执行Select语句读取tb_account数据,读取的结果正确(1000,1000).

  事务A里面提交了事务。然后事务B再次做Select操作查询结果也正确(500,1500)

  问题:事务B在一次事务中对tb_account表做了两次select操作,两次操作查询的结果不一致。

幻读:

事务A插入一条数据,能够使用select获取结果,此时事务B几乎同时插入了一条或者大量数据,此时事务A看不到事务B的更新(破坏了一致性,insert)。

read uncommitted脏读测试:

f67e3147f2ff45fbbed5c9a1edb7c4f5.png

 开启一个事务,不用Committed提交,另一个事务就可以读到这个事务的语句更新了

如何解决脏读问题?修改事务隔离级别:读已提交

set session transaction isolation level read committed;

5daaa016c45a40418485f6987095cc4c.png

如何解决不可重复读问题? 将事务隔离级别设置为"可重复读 " repeatable read 

076df366e0d4488d9f087aba635263af.png

幻读问题演示:

bddd074a429642bc858db7ac0a4fb183.png 

串行化serializable测试

能够解决所有的问题,但是效率低下,它类似Java的synchronized

Java使用synchronized用来锁对象。MySQL使用serializable锁表,事务A开启事务,做了DML操作,但是没有提交。此时事务B开启事务,执行select操作,没有查询到数据,因为此时tb_account表被事务A占用了(锁住了)。

set session transaction isolation level serializable;

 3d470f16220b417aa5cfec7b7a5c0db8.png

猜你喜欢

转载自blog.csdn.net/shengshanlaolin_/article/details/128460801