资料: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.

 

      

        

     

 posted on 2013-05-30 17:55  evencao  阅读(238)  评论(0编辑  收藏  举报