【14】事务的四大特征

1、事务的四大特征

A:原子性:事务是最小的单位,不可以在分割;

C:一致性:事务要求,同一事务中的sql语句,必须保证同时成功或同时失败;

I:隔离性:事务1和事务2之间是具有隔离性的;

D:持久性:事务一旦结束,就不可以返回。

事务开启方式:

1.修改默认提交;

2.begin;

3.start transaction;

事务提交:

commit;

事务手动回滚:

rollback;

2、事务的隔离性:

1.read uncommitted; 读未提交的

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

mysql> INSERT INTO user VALUES(3,'小明',1000);
mysql> INSERT INTO user VALUES(4,'淘宝',1000);
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
+----+------+-------+

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

系统级别:

mysql> select @@global.transaction_isolation;

会话级别:

mysql> select @@transaction_isolation;

默认的隔离级别:

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

如何修改隔离级别?

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

 eg.小明买鞋

成都的小明转账800:

mysql> start transaction;
mysql> update user set money=money-800 where name='小明';
mysql> update user set money=money+800 where name='淘宝';
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |   200 |
|  4 | 淘宝 |  1800 |
+----+------+-------+

广州的淘宝查收:

mysql> use bank;
Database changed
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |   200 |
|  4 | 淘宝 |  1800 |
+----+------+-------+

之后成都的小明:

mysql> rollback;
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
+----+------+-------+

之后广州的淘宝才发现:

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
+----+------+-------+

如果两个不同的地方都在进行操作,事务A(小明)开启之后,它的数据仍可以被其他事务B(广州)读取到。这样就会出现(脏读)。

脏读:一个事务读到了另外一个事务没有提交的数据。实际上开发是不允许脏读出现的。

2.read committed; 读已提交的

修改隔离级别并查看:

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

eg.

银行的会计小张:

mysql> start transaction;
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
+----+------+-------+

小张出去上厕所了。

此时的小王:

mysql> use bank;
Database changed
mysql> start transaction;
mysql> insert into user values(5,'c',100);
mysql> commit;
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
+----+------+-------+

小张回来了:

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

咦?money的平均值不应该是1000么?怎么变成了820?

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

此称为:不可重复读现象。

3.repeatable read; 可以重复读

 修改隔离级别并查看:

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

在REPEATABLE-READ隔离级别下又会出现什么问题?

张全蛋在成都

mysql> start transaction;

王尼玛在北京

mysql> start transaction;

张全蛋在成都

mysql> insert into user values(6,'d',1000);
mysql> commit;
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
|  6 | d    |  1000 |
+----+------+-------+

王尼玛在北京

mysql> insert into user values(6,'d',1000);
ERROR 1062 (23000): Duplicate entry '6' for key 'PRIMARY'
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
+----+------+-------+

这种现象叫幻读

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

4.serializable; 串行化

 修改隔离级别:

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

当前记录:

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
|  6 | d    |  1000 |
+----+------+-------+

张全蛋在成都

mysql> start transaction;

王尼玛在北京

mysql> start transaction;

张全蛋在成都

mysql> insert into user values(7,'铁柱',1000);
mysql> commit;
mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
|  6 | d    |  1000 |
|  7 | 铁柱 |  1000 |
+----+------+-------+

王尼玛在北京

mysql> select * from user;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | a    |   900 |
|  2 | b    |  1100 |
|  3 | 小明 |  1000 |
|  4 | 淘宝 |  1000 |
|  5 | c    |   100 |
|  6 | d    |  1000 |
|  7 | 铁柱 |  1000 |
+----+------+-------+

张全蛋在成都

mysql> insert into user values(8,'小花',1000);

sql语句会卡住,直到王尼玛commit。

当user表被另外一个事务操作的时候,其他事务里面的写操作是不可以进行的。进入排队状态(串行化)。

直到王尼玛事务结束以后,张全蛋的写入操作才会执行。

串行化的问题是:性能特差。性能:

READ-UNCOMMITTED (脏读)> READ COMMITTED > REPEATABLE READ(幻读) > SERIALIZABLE

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

 

posted @ 2020-04-15 13:48  闪亮可可仙  阅读(275)  评论(0编辑  收藏  举报