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