Todd

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            65 隨筆 :: 0 文章 :: 24 評論 :: 0 Trackbacks

          1.事務里一些有問題的讀取:臟讀,不可重復讀,幻象讀

          臟讀 (dirty read)事務T1更新了一行記錄的內容,但是并沒有提交所做的修改。事務T2讀取更新后的行,然后T1執行回滾操作,取消了剛才所做的修改。現在T2所讀取的行就無效了。

          不可重復讀取 (nonrepeatable read)事務T1讀取一行記錄,緊接著事務T2修改 了T1剛才讀取的那一行記錄。然后T1又再次讀取這行記錄,發現與剛才讀取的結果不同。這就稱為“不可重復”讀,因為T1原來讀取的那行記錄已經發生了變化。

          幻像讀取 (phantom read)事務T1讀取一條指定的WHERE子句所返回的結果集。然后事務T2新插入 一行記錄,這行記錄恰好可以滿足T1所使用的查詢條件中的WHERE 子句的條件。然后T1又使用相同的查詢再次對表進行檢索,但是此時卻看到了事務T2剛才插入的新行。這個新行就稱為“幻像”,因為對T1來說這一行就像突 然出現的一樣。

          2.事務的隔離級別

          從級別低到高依次為:

          READ UNCOMMITTED 幻像讀、不可重復讀和臟讀都允許。

          READ COMMITTED 允許幻像讀、不可重復讀,但不允許臟讀。

          REPEATABLE READ 允許幻像讀,但不允許不可重復讀和臟讀。InnoDB默認級別

          SERIALIZABLE 幻像讀、不可重復讀和臟讀都不允許。

          但是InnoDB的可重復讀隔離級別和其他數據庫的可重復讀是有區別的,不會造成幻象讀(phantom read)。

          ORACLE數據庫支持 READ COMMITTED 和 SERIALIZABLE ,不支持 READ UNCOMMITTED 和 REPEATABLE READ 。

          3.測試:

          1)并發更新 ,表tab1 的一條記錄id=1 num=1,兩個session分別執行事務1,2

          分別輸入下面的語句

          事務1 (session1) :

          ?????????? start transaction;

          ?????????? update tab1 set num=num+1 where id=1;

          =========

          一條記錄被更新,select發現num=2;

          事務2 (session2):

          ?????????? start transaction;

          ?????????? update tab1 set num=num+1 where id=1;

          =========

          事務2會被阻塞,然后session1輸入commit;提交事務1。此時事務2更新成功。

          session1 select一下會發現num還是2(不允許臟讀 );session2 select 一下 num 為3(update可以得到最新提交過的數據然后更新,但是如果沒有update,一直是select 的話select得到的num一直是1 ),然后commit;

          session1 select 發現num為3 ,session2 select 發現num為3;

          所以,事務中update是有行寫鎖(排他鎖)的,不會發生: 臟讀和不可重復讀(對于自身有update的事務,update之后是可以讀到最新數據的,這屬于例外?^_^ ),

          2)關于幻象讀 ,innodb默認事務隔離級別是不會出現的;摘自網上,測試通過:

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

          session 1 創建表并插入測試數據

          mysql> create table test(i int) engine=innodb;
          Query OK, 0 rows affected (0.00 sec)

          mysql> insert into test values(1);
          Query OK, 1 row affected (0.00 sec)
          session 2 查詢,沒有數據,正常,session1沒有提交,不允許臟讀

          mysql> select * from test;
          Empty set (0.00 sec)
          session 1 提交事務

          mysql> commit;
          Query OK, 0 rows affected (0.00 sec)
          session 2 查詢,還是沒有數據,沒有產生幻象讀

          mysql> select * from test;
          Empty set (0.00 sec)
          4.最后,現在應該知道數據庫并發控制并不復雜,交給數據庫的事務就行,mysql 選用innodb引擎,不會出現:“不可重復讀”(就是在事務1進行數據修改的時候,事務2讀取的數據是沒修改 之前的數據,事務1提交的時候,事務2再次讀取的時候得到的是修改后的數據,單個事務內所讀數據不一致),“臟讀”,“幻象讀”;

          ?關于innodb鎖機制的詳細解釋,參見《mysql手冊》-“15.2.10 .? InnoDB 事務模型和鎖定”。


          本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/todd_liu/archive/2010/09/10/5875650.aspx

          posted on 2010-09-11 15:50 Todd 閱讀(5255) 評論(0)  編輯  收藏 所屬分類: DB
          主站蜘蛛池模板: 文安县| 荣成市| 石城县| 龙江县| 满城县| 安乡县| 湟源县| 泗洪县| 历史| 宜黄县| 宾川县| 健康| 宜兴市| 巴里| 都兰县| 孝昌县| 河北省| 全椒县| 宁乡县| 林口县| 马关县| 桐乡市| 大化| 合作市| 民乐县| 商河县| 顺平县| 金阳县| 灵山县| 高阳县| 辰溪县| 长沙县| 福海县| 瑞安市| 交城县| 南开区| 方城县| 祁门县| 余干县| 睢宁县| 吉安县|