什么是事务

一个事务是一个完整的是业务逻辑单元,不可再分。
比如:银行账户转账,从A账户向B账户转账10000,需要执行两条update语句:
update t_act set balance = balance - 10000 where actno = ‘act-001’;
update t_act set balance = balance + 10000 where actno = ‘act-002’;

以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。
要想保证以上两个DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。

事务相关语句

和事务相关的语句只有:DML语句(insert delete update)
因为DML语句和数据库表的“数据”相关。

事务存在的目的

事务存在是为了保证数据的完整性和安全性。

事务的特性

事务包括四大特性: ACID
A:原子性:事务是最小的工作单元,不可再分。
C:一致性:事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性:事务A与事务B之间具有隔离。
D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功。

事务之间的隔离性

第一级别

读未提交(**read uncommitted):对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
读未提交存在脏读现象:表示读到了脏数据。**

第二级别

读已提交(**read committed):对方事务提交之后的数据我方可以读取到。
读已提交解决了脏读现象。
读已提交存在不可重复读取的问题。**

第三级别

可重复读取(**repeatable read**)
可重复读取解决了不可重复读取的问题。
可重复读取存在读到的数据是幻想问题。

第四级别

序**列化/串行化(serializable)
存在读取效率低问题,需要事务排队。**

演示事务

关闭自动提交和开始事务的关系

set autocommit=0,
当前session禁用自动提交事物,自此句执行以后,每个SQL语句或者语句块所在的事务都需要显示”commit/rollback”才能提交事务。
start transaction
指的是启动一个新事务。

在默认的情况下,MySQL从自动提交(autocommit)模式运行,这种模式会在每条语句执行完毕后把它作出的修改立刻提交给数据库并使之永久化。事实上,这相当于把每一条语句都隐含地当做一个事务来执行。如果你想明确地执行事务,需要禁用自动提交模式并告诉MySQL你想让它在何时提交或回滚有关的修改。
执行事务的常用办法是发出一条START TRANSACTION(或BEGIN)语句挂起自动提交模式,然后执行构成本次事务的各条语句,最后用一条 COMMIT语句结束事务并把它们作出的修改永久性地记入数据库。万一在事务过程中发生错误,用一条ROLLBACK语句撤销事务并把数据库恢复到事务开 始之前的状态。
START TRANSACTION语句”挂起”自动提交模式的含义是:在事务被提交或回滚之后,该模式将恢复到开始本次事务的 START TRANSACTION语句被执行之前的状态。(如果自动提交模式原来是激活的,结束事务将让你回到自动提交模式;如果它原来是禁用的,结束当前事务将开始下一个事务。)
如果是autocommit模式,autocommit的值应该为1,否则autocommit的值是0;请在试验前确定autocommit的模式是否开启。

mysql事务自动提交

  1. drop table if exists t_user;
  2. create table t_user
  3. (
  4. id int primary key auto_increment,
  5. username varchar(20)
  6. );
  7. insert into t_user(username) values('zhangsan');
  8. mysql> select * from t_user;
  9. +----+----------+
  10. | id | username |
  11. +----+----------+
  12. | 1 | zhangsan |
  13. +----+----------+
  14. 1 row in set (0.00 sec)
  15. rollback;
  16. mysql> select * from t_user;
  17. +----+----------+
  18. | id | username |
  19. +----+----------+
  20. | 1 | zhangsan |
  21. +----+----------+
  22. 1 row in set (0.00 sec)

关闭事务自动提交

关闭自动提交:set autocommit=0;

set autocommit=0;

insert into t_user(username) values('lisi');
insert into t_user(username) values('wangwu');

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
+----+----------+
3 rows in set (0.06 sec)

rollback;

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
+----+----------+
1 row in set (0.00 sec)

演示事务隔离级别

第一:演示read uncommitted

设置事务隔离级别:**set global transaction isolation level read uncommitted;
查看事务的全局隔离级别:**select @@global.transaction_isolation;

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

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

窗口1:

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

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
+----+----------+
3 rows in set (0.00 sec)

--窗口2插入数据

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
|  6 | jack     |
+----+----------+
4 rows in set (0.01 sec)

窗口2:

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

mysql> insert into t_user(username) values('jack');
Query OK, 1 row affected (0.01 sec)

第二:演示read committed

设置事务隔离级别:**set global transaction isolation level read committed;
查看事务的全局隔离级别:**select @@global.transaction_isolation;

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                 |
+--------------------------------+
1 row in set (0.00 sec)

窗口1:

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

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
+----+----------+
3 rows in set (0.01 sec)

--窗口2插入数据,但未提交

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
+----+----------+
3 rows in set (0.00 sec)

--窗口2提交commit

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | lisi     |
|  5 | wangwu   |
|  7 | jack     |
+----+----------+
4 rows in set (0.00 sec)

窗口2:

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

mysql> insert into t_user(username) values('jack');
Query OK, 1 row affected (0.01 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

第三:演示read committed

设置事务隔离级别:**set global transaction isolation level repeatable read;
查看事务的全局隔离级别:**select @@global.transaction_isolation;

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

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

窗口1:

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

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  8 | zhangsan |
|  9 | lisi     |
| 10 | wangwu   |
+----+----------+
3 rows in set (0.00 sec)

--窗口2执行delete删除提交

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  8 | zhangsan |
|  9 | lisi     |
| 10 | wangwu   |
+----+----------+
3 rows in set (0.01 sec)

窗口2:

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

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  8 | zhangsan |
|  9 | lisi     |
| 10 | wangwu   |
+----+----------+
3 rows in set (0.00 sec)

mysql> delete from t_user;
Query OK, 3 rows affected (0.00 sec)

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

mysql> select * from t_user;
Empty set (0.00 sec)

不可使用truncate删除

mysql> truncate table t_user;
^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted

第四:演示serializable

设置事务隔离级别:**set global transaction isolation level serializable;
查看事务的全局隔离级别:**select @@global.transaction_isolation;

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)

窗口1:

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

mysql> select * from t_user;
Empty set (0.01 sec)

mysql> insert into t_user(username) values('zhangsan');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 11 | zhangsan |
+----+----------+
1 row in set (0.00 sec)

--窗口2执行查询被卡住

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

--窗口1提交后窗口2继续执行

窗口2:

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

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
| 11 | zhangsan |
+----+----------+
1 row in set (19.79 sec)