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默认是开启事务的(自动提交)。

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)

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

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

rollback;

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
+----+------+-------+
1 row in set (0.00 sec)
//回滚无效

----设置mysql自动提交为false;

set autocommint=0;
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
+----+------+-------+
1 row in set (0.00 sec)

mysql> insert into user values(2,'b',1000);
Query OK, 1 row affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
|  2 | b    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
+----+------+-------+
1 row in set (0.00 sec)

//插入命令后,输入commit,再rollback不会回滚;

mysql> insert into user values(2,'b',1000);
Query OK, 1 row affected (0.00 sec)
//手动提交数据
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
|  2 | b    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)
//再撤销,是不可以撤销的(持久性)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |  1000 |
|  2 | b    |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)

----自动提交?
@@autocommit=1;
----手动提交?
commit;
----事务回滚?
rollback;自动提交时,不能回滚,手动提交前,事务可回滚,手动提交后,事务不可回滚。

----事务给我们提供了一个返回的机会。


mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@autocommit=1;
+----------------+
| @@autocommit=1 |
+----------------+
|              1 |
+----------------+
1 row in set (0.00 sec)

----手动开启事务;
----begin;
或者start transaction;
都可以帮我们手动开启一个事务。
但是事务开启之后,一旦commit提交,事务不可回滚(即当前事务结束)。

mysql> update user set money=money-100 where name='a';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set money=money+100 where name='b';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
+----+------+-------+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
+----+------+-------+
2 rows in set (0.00 sec)
ysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set money=money-100 where name='a';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set money=money+100 where name='b';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
+----+------+-------+

----事务的四大特征:
A:原子性:事务是最小的单位,不可在分割。
C:一致性:事务要求,同一事务中的 sql 语句,必须保证同时成功或同时失败。
I:隔离性:事务1 和事务2 之间是具有隔离性的。
D:持久性:事务一旦结束(commit,rollback),就不可返回。

----事务开启:
1、修改默认提交 set autocommit = 0;
2、begin;
3、start 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,'xiaoming',1000);
insert into user values(4,'taobaodian',1000);

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

select @@global.transaction isolation;

查看会话级别:

select @@transaction isolation;

----如何修改数据库的隔离级别?

set global transaction isolation level read uncommitted;

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

start transaction;//事务开始
update user set money=money-800 where name='xiaoming';
update user set money=money+800 where name='taobaodian';
ysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |   200 |
|  4 | taobaodian |  1800 |
+----+------------+-------+
//淘宝店查询到账,发货,吃饭
mysql> rollback;//小明操作回滚
Query OK, 0 rows affected (0.00 sec)

//淘宝店吃过饭,付账发现钱不对
mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
+----+------------+-------+
4 rows in set (0.00 sec)

----淘宝店看到了小明未提交的数据,即读未提交。

----read uncommitted;
如果两个不同的地方,都在进行操作,如果事务a 开启之后,他的数据可以被其他事务读取到;这样就会出现脏读。
脏读:一个事务读到了另外一个事务没有提交的数据。
实际开发是不允许脏读出现的。

----read commit
修改数据库隔离级别;

mysql> set global transaction isolation level read 
committed;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| READ-COMMITTED                 |
+--------------------------------+

bank数据库 user表
小张:银行的会计

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
+----+------------+-------+
4 rows in set (0.00 sec)

小张休息抽烟中…

小王:

start transaction;
insert into user values(5,'c',100);
commit;
mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
|  5 | c          |   100 |
+----+------------+-------+

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

ysql> select avg(money) from user;
+------------+
| avg(money) |
+------------+
|   820.0000 |
+------------+
1 row in set (0.00 sec)

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

----虽然我只能读到另外一个事务提交的数据,但还是会出现问题,就是读取同一个表的数据,发现前后不一致;
即不可重复读现象:read committed;

3、repeatable read; 可以重复读

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

在repeatable read 隔离级别下又会出现什么问题?

mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
|  5 | c          |   100 |
+----+------------+-------+
5 rows in set (0.00 sec)

----张全蛋-程度

start transaction;

----王尼玛-北京

start transaction;

----张全蛋-成都

insert into user values(6,'d',1000);
mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
|  5 | c          |   100 |
|  6 | d          |  1000 |

commit;//提交

----王尼玛-北京

//再开一终端
mysql> select * from user;
+----+------------+-------+
| id | name       | money |
+----+------------+-------+
|  1 | a          |   800 |
|  2 | b          |  1200 |
|  3 | xiaoming   |  1000 |
|  4 | taobaodian |  1000 |
|  5 | c          |   100 |
+----+------------+-------+

mysql> insert into user values(6,'d',1000);
ERROR 1062 (23000): Duplicate entry '6' for key 'PRIMARY'

----这种现象就叫做幻读!!!
事务a 和事务b 同时操作同一张表,事务a提交的数据,也不能被事务b读到,就可以造成幻读。

4、serializable; 串行化

//修改隔离级别为串行化
mysql> set global transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@global.transaction_isolation;
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| SERIALIZABLE                   |
+--------------------------------+
1 row in set (0.00 sec)

张全蛋-成都

start transaction;
insert into user values(8,'wangxiaohua',1000);
//sql语句被卡主了?

王尼玛-北京

start transaction;
select * from user;

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

----直到进入排队状态(串行化),直到另一个事务结束之后(commit),其他事务的写入操作才会执行。

----在没有等待超时的情况下,其他事务会立即执行。

----串行化问题时,性能特差。

READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE;

----隔离级别越高,性能越差。
mysql 默认隔离级别是 REPEATABLE-READ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值