事务


此系列记录PN视频学习笔记



* 本博客涉及到的数据为bjpowernode.sql,SQL文见MySQL入门(9)文末。

* 该数据有三张表,分别是部门表dept(deptno部门编号、dname部门名称、loc位置)、

                                       员工表emp(empno工号、ename员工姓名、job职位、mgr直属领导工号、

                                                            hiredate入职日期、sal月薪、comm补贴、deptno部门编号)、

                                        薪水等级表salgrade(grade等级、losal区间下限、hisal区间上限)


事务

    1、什么是事务?

       -事务对应的英语单词:Transaction

       -事务:  * 一个‘最小’的‘不可再分’的工作单元。

                    * 通常一个事务对应了一个完整的业务。【例如:银行账户转账业务,该业务就是一个最小的工作单元】

                    * 而一个完整的业务需要一个批量的DML(insert,update,delete)语句共同联合完成

                    * 事务只和DML语句有关系,或者说DML语句才有事务

                    * 以上所描述的‘批量的DML语句’共有多少条DML语句,这个和业务逻辑有关系,业务逻辑不同,DML语句的个数不同

 

    2、关于银行账户转账操作,账户转账是一个完整的业务,最小的单元,不可再分,也就是说银行账户转账是一个业务。

       t_act账户表

       actno             balance

       -------------------------------------

       act-001           50000.0

       act-002           10000.0

       执行转账操作(10000):

           updatet_act set balance = 40000.0 where actno = ‘act-001’;

           updatet_act set balance = 20000.0 where actno = ‘act-002’;

       以上两条DML语句要求必须同时成功或者同时失败,最小单元,不可再分。当第一条DML语句执行成功之后,并不能将底层数据库中第一个账户的数据修改,只是将操作记录了一下,这个记录是在内存中完成的,当第二条DML执行成功之后,和底层数据文件的数据完成同步。若第二条DML语句执行失败,清空所有历史操作记录。要完成以上功能,必须借助事务。

 

    3、事务的四个特征(ACID)

       -原子性(A)

              *事务是最小的工作单元,不可再分

       -一致性(C)

              *事务要求所有的DML语句操作的时候,必须同时成功或者同时失败

       -隔离性(I)

              *事务A和事务B之间具有隔离

       -持久性(D)

              *是事务的保证,事务终结的标志。【内存中的数据持久到硬盘文件中】

 

    4、关于一些术语【不是SQL语句】

       -开启事务: start transaction

       -结束事务: end transaction

       -提交事务: commit transaction

       -回滚事务: rollback transaction

 

    5、和事务有关的两条重要的SQL语句【TCL】

       commit       提交

       rollback      回滚

 

    6、事务开启和结束的标志

       -开始的标志:

              任何一条DML(insert,update,delete)语句的执行,标志的事务的开启

       -结束的标志:

              提交或者回滚

              提交:成功的结束,将所有DML操作历史记录和底层硬盘文件中的数据进行同步

              回滚:失败的结束,将所有DML语句操作历史记录全部清空

 

    7、重点:

       在事务进行过程中,未结束之前,DML语句是不会更改底层数据库文件的数据,只是将历史操作记录一下,在内存中完成记录,只有在事务结束的时候,而且是成功的结束的时候才会修改底层硬盘文件中的数据。

 

    8、在MYSQL数据库管理系统中,事务的提交和回滚的演示

       -在MYSQL数据库管理系统中,默认情况下,事务是自动提交的额,也就是说,只要执行一条DML语句,开启事务即提交事务。

 

       -这种自动提交机制是可以关闭的【关闭的第一种方式】

           starttransaction; 手动开启事务

           DML语句...

           DML语句...

           DML语句...

           DML语句...

           commit;           手动提交事务【事务成功的结束】

 

            start transaction; 手动开启

           DML语句...

           DML语句...

           DML语句...

           DML语句...

           rollback;         手动回滚事务【事务失败的结束】

 

       -关闭自动提交的第二种方式

           setaotucommit = on/off;

           setsession aotucommit = on/off;

           mysql>show variables like '%commit%';

       以上打开和关闭自动提交机制,只对当前会话有效

+-----------------------------------------+-------+

| Variable_name                           | Value |

+-----------------------------------------+-------+

| autocommit                              | OFF   |

| binlog_group_commit_sync_delay          | 0     |

| binlog_group_commit_sync_no_delay_count | 0     |

| binlog_order_commits                    | ON    |

| innodb_api_bk_commit_interval           | 5     |

| innodb_commit_concurrency               | 0     |

| innodb_flush_log_at_trx_commit          | 1     |

| slave_preserve_commit_order             | OFF   |

+-----------------------------------------+-------+

mysql> set autocommit = on;

mysql> show variables like '%commit%';

+-----------------------------------------+-------+

| Variable_name                           | Value |

+-----------------------------------------+-------+

| autocommit                              | ON    |

| binlog_group_commit_sync_delay          | 0     |

| binlog_group_commit_sync_no_delay_count | 0     |

| binlog_order_commits                    | ON    |

| innodb_api_bk_commit_interval           | 5     |

| innodb_commit_concurrency               | 0     |

| innodb_flush_log_at_trx_commit          | 1     |

| slave_preserve_commit_order             | OFF   |

+-----------------------------------------+-------+

 

    9、事务的四个特性——隔离性(isolation)

       9.1事务A和事务B之间具有一定的隔离性

       9.2 隔离性的四个级别:

           -read uncommited    读未提交

           -read commited      读已提交

           -repeatable read    可重复读

           -serializable       串行化

 

       9.3 read uncommited 读未提交

           -事务A和事务B ,事务A未提交的数据,事务B可以读取到。

           -这里读取到的数据可以叫做‘脏数据’,或者叫‘dirty read’

           -这种隔离级别是最低级别,这种级别一般都是在理论上存在的,数据库默认的隔离级别,一般都是高于该隔离级别的。

 

       9.4 read commited  读已提交

           -事务A和事务B ,事务A提交的数据,事务B才能读取到。换句话说:对方事务提交之后的数据,当前事务才能读取到。

           -这种隔离级别可以避免脏数据,高于上面的读未提交的隔离级别。

           -这种隔离级别会导致‘不可重复读取’

           -oracle数据库管理系统默认的隔离级别

 

       9.5 repeatable read  可重复读

           - 事务A和事务B ,事务A提交之后的数据,事务B读取不到。换句话说,对方提交之后的数据我还是读取不到。

           - 事务B是可重复读取数据的,不同时间读取一条数据得到一个结果(缓存中的数据)

           - 这种隔离级别可以避免‘藏独和不可重复读取’,达到可重复读取,高于读已提交隔离级别

           - 虽然可以达到‘可重复读’的效果,但是会导致‘幻想读’

           - MYSQL数据库管理系统默认的隔离级别

 

       9.6 serializable 串行化

           -事务A和事务B,事务A在操作数据库表中数据的时候,事务B只能排队等待,事务A和事务B是串行执行,不再并发

           -这种事务隔离级别一般很少使用,吞吐量太低,用户体验不好

           -这种隔离级别可以避免‘幻想读’,每一次读取的都是数据库表中真是的记录


     10、设置事务的隔离级别

       10.1 第一种方式:修改my.ini配置文件

              使用transaction-isolation选项来设置服务器的缺省事务隔离级别

              可选值:read-uncommited;read-commited;repeatable-read;serializable

              ------------------my.ini-------------------------

               [mysqld]

              transaction-isolation= read-uncommited

 

       10.2 第二种方式:使用命令方式设置事务的隔离级别

           可选值:read-uncommited;read-commited;repeatable-read;serializabl

set [无/session/global] transaction isolation level read-uncommited;

           默认是会话级(设置隔离级别作用于当前回话),而不是全局级(设置隔离级别作用于全局)。

 

   11、查看事务的隔离级别

       查看当前回话的事务隔离级别

       select @@tx isolation;

       select@@session isolation;

       查看当前全局的事务隔离级别

       select @@globalisolation;

 

    12、并发事务与隔离级别示例

       12.1 读未提交 read uncommited

       会话1                                                                                      会话2

       ------------------------------------------------------------------------------------------------------------

       setglobal transaction isolation level read uncommited;

        select @@tx isolation;(若报错,需要重新打开)

       usebjpowernode;                                                                    use bjpowernode

       starttransaction;                                                                      start transaction;

       inserttable t_user(name) values(‘king’);                              select * from t_user;(查询到)

 

       12.2 读已提交 read commited

       会话1                                                                               会话2

       ------------------------------------------------------------------------------------------------------------

       setglobal transaction isolation level read commited;

       select@@tx isolation;

       usebjpowernode;                                                               use bjpowernode

       starttransaction;                                                                 start transaction;

       inserttable t_user(name) values(‘ford’);                         select * from t_user;(未查询到)

       commit;                                                                              select * from t_user;(查询到)

 

       12.3 可重复读 repeatable read

       会话1                                                                                  会话2

       ------------------------------------------------------------------------------------------------------------

       setglobal transaction isolation level repeatable read;

       select@@tx isolation;

       usebjpowernode;                                                               use bjpowernode

       starttransaction;                                                                 start transaction;

       select* from t_user;                                                            select * from t_user;(可查询)

       insert table t_user(name) values(‘luzhishen’);              

       commit;                                                                             select * from t_user;(和上一条结果一致)