zoukankan      html  css  js  c++  java
  • MySQL事务2013530

    资料:1.《MySQL技术内幕》SQL编程 2.《MySQL技术内幕》第四版

    事务(transcation)是数据库区别文件系统的重要特征之一。事务就是将作为一个不可分割的逻辑单元而被执行的SQL语句(DML语句),该组语句要么全部成功,要么全部失败。

    从理论上说事务应该是同时满足ACID特性。

    A(atomicity),原子性。就死构成事务的所有SQL语句都是一个逻辑单元,不可分割,不能只执行它们中的一部分。

    C(consistency),一致性。即你在事务开始前和事务执行完之后,数据库的完整性没有被破坏,必须是稳定的。换句话说就是不应该经过执行事务之后吧你的数据库搞的一团乱。

    I (isolation),隔离性。每个事务对其他的事务都是不可见的,不应该互相影响。

    D(dirable),持久性。事务一旦提交,其结果时永远的被记录到数据库系统中。

    MySQL是否支持事务安全是由数据引擎决定的,比如或MySQL的Innodb存储引擎和Falcon存储引擎是支持事务,而MyISAM存储引擎不支持事务安全性。

    就以上的举个例子:A去银行转账,将100块钱转给B。银行系统需要作出的就是从A的账户上减去100,在B的账户上加上100。        

             update transcation1 set menory = (menory-100) where name='A';
             update transcation1 set menory = (menory+100) where name='B';
    

      但是如果在万一银行在执行的过程中发生了意外,第一条语句执行完了。整个操作将不完整。A的账户了可以少了100,但是B的账户没有增加。如果没有事务,那就必须去手动去修改为原来的状态。

          就是事务的原子性,这两条语句必须是做为一个单元,要么全部失败,要么全部成功,数据也能和原来保持一致了。

          在MySQL命令行下的默认设置下,事务都是自动提交的,即当语句执行后就马上执行commit操作。用户对事务的控制语句主要有这些

          1.start transction或者begin:显示的开启一个事务,即不commit之前将不会自动提交。

            commit或者rollback:提交或者回滚。

            这一组一般都是一起的,所以再这里一起讨论。

        create table t(a_id int unsigned auto_increment,primary key(a_id),name varchar(10) not null,menory decimal(10,2));这是上面的例子创建的表
    

       首先插入两条数据

     insert into t values (null,'A',100.00),(null,'B',100.00);
    select * from t;
    a_id  name menory
    1 A 100.00
    2 B 100.00

      

      如果再银行需要再增加一个账户

    mysql> start transaction;
    mysql> insert into t values(null,'C',1.00);
    

      此时如果你启动另外一个mysql程序的实力后查询这个表格在提交之前是无法查询到的。结果还是原来的两条数据。当在commit之后另一个mysql窗口中才能看到。

         如果在插入D客户之后你发现这个D客户的金额数出错了,不要commit,直接rollback。之后再commit 也不会插入Dz这个客户。

    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'D',2.
    Query OK, 1 row affected (0.00 sec)
    
    mysql> rollback;
    Query OK, 0 rows affected (0.04 sec)
    
    mysql> commit;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select* from t;
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    1 | A    | 100.00 |
    |    2 | B    | 100.00 |
    |    3 | C    |   1.00 |
    +------+------+--------+
    3 rows in set (0.00 sec)
    

     显示的开始一个事务使用begin 和start transaction是等价的。

       还有一种开始一个事务的方法就是set autocommit来开始事务,例

    重新将表格清空,方便看清楚
    mysql> truncate table t;
    Query OK, 0 rows affected (0.07 sec)
    
    mysql> select * from t;
    Empty set (0.00 sec)
    
    mysql> set autocommit=0;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'A',200.00
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into t values(null,'B',200.00
    Query OK, 1 row affected (0.00 sec)
    
    mysql> select * from t;  插入两行后查询表有这两行
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    1 | A    | 200.00 |
    |    2 | B    | 200.00 |
    +------+------+--------+
    2 rows in set (0.00 sec)
    
    mysql> rollback;
    Query OK, 0 rows affected (0.07 sec)
    
    mysql> select * from t;         执行rollback后查询表为空
    Empty set (0.00 sec)
    
    mysql> insert into t values(null,'A',200.00
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into t values(null,'B',200.00
    Query OK, 1 row affected (0.00 sec)
    
    mysql> commit;
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> select * from t;
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    3 | A    | 200.00 |
    |    4 | B    | 200.00 |
    +------+------+--------+
    2 rows in set (0.00 sec)
    
    mysql> insert into t values(null,'C',200.00           commit前两条之后插入第三条
    Query OK, 1 row affected (0.00 sec) 
    
    mysql> rollback;                                      
    Query OK, 0 rows affected (0.11 sec)
    
    mysql> select * from t;                  rollback后还是没有插入C到t表,说明还是没有自动提交,需要你去手动的设置autocommit=1;不向start transaction那样能回到事务之前的状态
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    3 | A    | 200.00 |
    |    4 | B    | 200.00 |
    +------+------+--------+
    2 rows in set (0.00 sec)
    

      2.savepoint identifier:savepoint允许在事务中创建一个保存点,一个事务中可以有多个savepoint;

          例:还是使用之前的表,清空之前的表,其实在start transaction是隐式的创建了一个savepoint.

    mysql> select *from t;
    Empty set (0.00 sec)
    
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'A',200.00);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into t values(null,'B',200.00);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> savepoint mypoint_1;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'C',200.00);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> rollback to savepoint mypoint_1;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'D',200.00);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> commit;
    Query OK, 0 rows affected (0.04 sec)
    
    mysql> select * from t;   结果是C没有被插入
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    1 | A    | 200.00 |
    |    2 | B    | 200.00 |
    |    4 | D    | 200.00 |
    +------+------+--------+
    3 rows in set (0.00 sec)

      3.release savepoint identifier:删除一个事务的保存点,当没有一个保存点执行这句话,会抛出一个异常。这里就不做例子了。

         此外commit和commit work语句基本上是一致的,都用来提交事务的。不同之处在于commit work用来控制事务结束后的行为时chain还是release。

         如果是chain那么事务就成了链式事务了。可以使用completion_type来进行控制,默认该参数为0,

         当completion_type的参数为1时,commit work就等同于commit and chain,表示马上自动开启一个相同的隔离界别的事务。

         例

    mysql> set @@completion_type=1;                       将completion_type设置为1,表示chain事务了。
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> begin
        -> ;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(null,'A',100.22);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into t values(null,'B',100.22);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> commit work;                                  插入两条记录后commit
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> insert into t values(null,'C',100.22);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> insert into t values(2,'D',100.22);       
    ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
    mysql> rollback;                                    这里rollback,后查询出来的只有A和B,说明C被回滚了,这里autocommit也是1说明是commit work时候有开始了一个隔离性的事务。
    Query OK, 0 rows affected (0.08 sec)
    
    mysql> select * from t;
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    1 | A    | 100.22 |
    |    2 | B    | 100.22 |
    +------+------+--------+
    2 rows in set (0.00 sec)
    

      当chompletion_type=2时,commit work等同于commit and release.当事务提交后会自动断开与服务器的连接。

         例:

    mysql> set @@completion_type=2;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> insert into t values(2,'D',100.22);
    ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
    mysql> insert into t values(null,'D',100.22);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> commit work;
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> select version();
    ERROR 2006 (HY000): MySQL server has gone away
    No connection. Trying to reconnect...
    Connection id:    5
    Current database: sampdb
    

      还有需要注意的在rollback to point后还需要显示的调用commit或者rollback命令。

          

         事务支持四种不同的隔离级别。

         这里先说说隔离级别,就是对事务的隔离性的控制,不然它会发生的问题:

          1.脏读:指某个事务为提交时,就可以被其他事务看到。其的事务认为数据行已经被修改了,但对数据行作出的修改那个事务还有可能会回滚,这肯定会导致数据表混乱。

          2.不可重复读取:指一个事务使用同一个select语句读取数据表的数据,但是另一个事务在两个select中间对数据行进行修改,这样两次读取的数据就不一样。

          3.幻影数据行:这不可重复读取时同一个原来,在第二个select前,另一个事务插入了数据行。

         再说说事务的这四个隔离级别(对于Innodb存引擎):

           READ UNCOMMITED:允许某个事务看到其他事务未提交的数据行动。

           READ COMMITED:只允许某个事务看到其他事务已经提交的数据行改动。

           REPEATABLE READ:即使有其他的事务在同时插入或数据行,这个事务所看到的结果也是一样的。在MySQL的Innodb中使用了Next-key lock锁算法(这个我不知道),因此避免了幻影数据行。                           

           SERIALIZABLE:在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新或插入记录,使事务串行执行,是四个隔离级别中限制最大的隔离级别,有可能会导致死锁或超时。并发度最低,慎用

          刚刚上面的例子,一个事务在为提交时,另一个mysql程序是看不到提交的数据的。上次是这样,因为InnoDB默认的隔离级别是repeatable read).

           这是mysql窗口1:此时没有进行commit

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

    mysql> use sampdb
    Database changed
    mysql> start transaction;

    Query OK, 0 rows affected (0.00 sec)

    mysql> insert into t values(null,'C',100);
    Query OK, 1 row affected (0.00 sec)

         窗口2的内容

    mysql> select * from t;
    +------+------+--------+
    | a_id | name | menory |
    +------+------+--------+
    |    1 | A    | 100.11 |
    |    2 | B    | 100.11 |
    |    3 | C    | 100.00 |
    +------+------+--------+
    3 rows in set (0.00 sec)
    

      这里窗口2的能看到窗口1插入的数据,但是还有commit.

          

            

         

  • 相关阅读:
    [转载] 长草颜文字的写给未来
    [彩蛋题] egg
    最近发现一些项目ignore文件没有生效,请使用下面方式清理下Cache
    freemarker显示含有html代码的内容
    数字化技术促进电网转型发展
    停更的时间里,我也在好好生活和工作
    iOS 开发问题集锦(一)
    SVN 在 Xcode中的状态说明
    virt-v2v命令将ESXI 虚机迁移到OpenStack中
    修改openstack镜像--支持root密码登陆
  • 原文地址:https://www.cnblogs.com/evencao/p/3108706.html
Copyright © 2011-2022 走看看