mysql事务

mysql事务
mysql中,事务是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性

比如银行转账:

a ——> -100

update user set money=money-100 where name ="a";

b——> +100

update user set money=money+100 where name ="b";

实际的程序中,如果只有一条语句执行成功了,而另外一条没有执行成功?

出现数据前后不一致

多条sql语句,可能会有同时成功的要求,要么同时失效

mysql中如何控制事务的
1.mysql是默认开启事务的(自动提交)

select @@autocommit;

默认事务开启的作用是:当我们去执行一个sql语句时,效果会立即体现出来,且不能回滚。

create database bank;
create table user(
id int primary key,
name varchar(20),
money int
);

insert into user values(1,"a",1000);

事务的提交与撤销

事务回滚:撤销sql语句执行效果

rollback;

设置mysql自动提交为false

set autocommit=0 #关闭了mysql自动提交功能

再次进行插入

insert into user values(2,"b",1000)#其实是虚拟数据,未被提交
rollback#可撤销上一步操作,

如何改变其虚拟存储的效果呢?在一条语句后紧接着放一个commit

insert into user values(3,"c",2000);
commit#相当于手动提交数据
rollback#再次回滚便没有效果,体现了事务的持久性......直接回滚到autocommit关闭处

update user set money=money-100 where name ="a";
update user set money=money+100 where name ="b";

事务给我们提供了一个反悔的语句

事务的分类

自动提交@@autocommit=1
手动提交commit
事务回滚rollback
begin;或者 start transction;

begin;或者 start transction;#可以手动开启一个事务,可以回滚相当于autocommit=0
commit #手动提交
事务的四大特征(ACID)
A 原子性:事务是最小的单位,不可以再分割
C一致性:事务要求,同一事务中的sql语句,必须同时成功或者同时失效
I 隔离性:事务1和事务2之间具有隔离性
D 持久性:事务一旦结束(commit,rollback:一旦commit就不能rollback;一旦rollback就不能commit),j就不可以返回
事务开启
1.修改默认提交 set autocommit=0;
2.begin;
3.star transaction;
事务手动提交
commit;#虚拟的效果真实产生
事务手动回滚
rollback ;#虚拟的效果被撤销
事务的隔离性
1.read uncommitted; #读未提交的
2.read committed; #读已提交的
3.repeatable read; #可以重复读
4.serializable ; #串行化

--------->1-read uncommitted<---------

如果有事务a和事务b,

a事务对数据进行操作,在操作过程中,事务没有被提交,但b可以看见a操作的结果。

bank数据库user表

insert into user values(3,"小明",1000);
insert into user values(4,"淘宝店",1000);
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+----+--------+-------+

---如何查看数据库的隔离级别?

select @@global.transaction_isolation;
select @@transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+

---如何修改隔离级别?

set global transaction isolation level read uncommitted;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| READ-UNCOMMITTED |
+--------------------------------+

--转账:小明在淘宝店买鞋子:800块钱

小明->成都 ATM

淘宝店 ->广州 ATM

begin;
update user set money=money-800 where name="小明";
update user set money=money+800 where name="淘宝店";
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | 200 |
| 4 | 淘宝店 | 1800 |
+----+--------+-------+

--给淘宝店打电话,说你去查一下,是不是到账饿了

--淘宝店在广州查账

+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | 200 |
| 4 | 淘宝店 | 1800 |
+----+--------+-------+

--发货

--晚上请女朋友吃好吃的

--1800

--小明在成都

rollback
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+----+--------+-------+

--结账时发现钱不够

select * from user;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | 1000 |
| 4 | 淘宝店 | 1000 |
+----+--------+-------+

总结

- 如果两个不同的地方,都在进行操作,如果a 开启之后,它的数据可以被其他事物读取到,这样就会出现脏读

- 脏读:一个事务读到另外一个事务没有提交的数据,就叫做脏读

-------->2.read committed<---------####

set global transaction isolation level read committed;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| READ-COMMITTED |
+--------------------------------+

bank 数据库user表

小张:银行的会计

begin;
select * from user;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | -600 |
| 4 | 淘宝店 | 2600 |
+----+--------+-------+

小张出去上厕所,抽烟

小王

begin;
insert into user values(5,"c",100);
commit;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | -600 |
| 4 | 淘宝店 | 2600 |
| 5 | c | 100 |
+----+--------+-------+

--小张上完厕所,抽完烟回来

select avg(money) from user;
+------------+
| avg(money) |
+------------+
| 820.0000 |
+------------+

--money的平均值不是1000,变少了?

-- 虽然只读到另外一个事务提交的数据,但还是会出现问题————读取同一个表的数据,发现前后不一致。

--不可重复现象:read commited

------------> repeatable read <---------------

set global transaction isolation level repeatable read;
select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+

---王尼玛-北京

begin;#同时打开begin
insert into user values(8,"铁柱",1000);;
+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | -600 |
| 4 | 淘宝店 | 2600 |
| 5 | c | 100 |
| 8 | 铁柱 | 1000 |
+----+--------+-------+

--张全蛋-成都

begin;#同时打开begin
insert into user values(8,"铁柱",1000);;

待修改!!!!!

+----+--------+-------+
| id | name | money |
+----+--------+-------+
| 1 | a | 800 |
| 2 | b | 1200 |
| 3 | 小明 | -600 |
| 4 | 淘宝店 | 2600 |
| 5 | c | 100 |
+----+--------+-------+
mysql> insert into user values(8,"铁柱",1000);
ERROR 1062 (23000): Duplicate entry '8' for key 'user.PRIMARY'

--这种现象就叫做幻读

----事务a和事务b 同时操作一张表时,事务a提交的数据,也不能被事务b读到,就可以造成幻读

--------> serializable(串行化) <--------

set global transaction isolation level serializable;
select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE |
+--------------------------------+

--张全蛋-成都

begin;
insert into user values(7,"赵铁柱",1000);

---王尼玛-北京

begin;
insert into user values(7,"赵铁柱",1000);

--sql语句被卡住了?

当输入commit时即刻会被执行

--当user表被另外一个事务操作执行的时候,其他事务里面的额写操作,是不可以进行的。

--进入排队状态(串行化),只有当一边的事务结束后,写入操作才会被执行

- 在没有等待超时的情况下

---串行化的问题:性能特差!!

性能总结

read uncommitted > read committed > repeatable read > serializable

-隔离级别越高,性能越差

-mysql默认隔离级别是repeatable read

记录学习的点点滴滴
原文地址:https://www.cnblogs.com/yangzilaing/p/14617269.html