事務

1. 事務概述

1.1 事務概念

    事務就是一件事情,這個事情可能有多個單元組成,要求這些單元要麼都成功要麼都不成功。

1.2 Mysql中的事務

(1)Mysql中默認事務處理

    在mysql登錄的情況下執行以下命令:showvariables like '%commit%';


     autocommint 值是 on,說明開啓自動提交(Oracle中 autocommit 默認就是 off)。mysql數據庫默認是開啓事務的,一條sql一個事務。oracle它默認情況下autocommit是off,就需要手動提交事務。關閉mysql的自動事務處理命令:

        set autocommit =off;( set autocommit = 0)

    如果設置autocommit 爲 off,意味着以後每條SQL 都會處於同一個事務中,相當於第一條SQL執行前執行了 start transaction。

(2)Mysql中常見事務操作命令

    starttransaction:-- 開啓事務一旦手動開啓了事務,事務自動提交失效.

    commit;-- 提交事務

    rollback;-- 事務回滾

1.3 JDBC中的事務

    java.sql.Connection接口中提供了關於事務操作的方法:

         setAutoCommit(boolean flag); 參數爲false相當於starttransaction

         commit(); 事務提交

         rollback(); 事務回滾

    設置事務回滾點:

        SavepointsetSavepoint(String name)

        在當前事務中創建一個具有給定名稱的保存點,並返回表示它的新 Savepoint 對象。

        例如:    Savepoint sp = conn.setSavepoint();

                   Conn.rollback(sp);

2. 事務的特性(ACID)

原子性(Atomicity):即表示事務中所有操作是不可再分割的原子單位。事務中所有操作要麼全部執行成功, 要麼全部執行失敗;
一致性(Consistency):事務執行後,數據庫狀態與其它業務規則保持一致。例如轉賬業務,無論事務執行成功與否,參與轉賬的兩個賬號餘額之和應該是不變的;
隔離性(Isolation):指在併發操作中,不同事務之間應該隔離開來,使每個併發中的事務不會相互干擾;
持久性(Durability):指的是一旦事務提交成功,事務中所有的數據操作都必須被持久化到數據庫中,即使提交事務後,數據庫馬上崩潰,在數據庫重啓時,也必須能保證通過某種機制恢復數據。

3. 事務的隔離級別

3.1 不考慮事務隔離性將會產生的問題

        多個線程開啓各自事務操作數據庫中數據時,數據庫系統要負責隔離操作,以保證各個線程在獲取數據時的準確性。如果不考慮隔離性,可能會引發如下問題:

    (1)髒讀:指一個事務讀取另一個事務未提交的數據

    (2)不可重複讀:在一個事務先後兩次讀取發生數據不一致情況,第二次讀取到另一個事務已經提交數據(強調數據更新 update

    (3)虛讀(幻讀) 在一個事務中,第二次讀取發生數據記錄數的不同,讀取到另一個事務已經提交數據(強調數據記錄變化 insert

3.2事務的4種隔離級別

數據庫內部定義了四種隔離級別,用於解決三種隔離問題

(1)SERIALIZABLE(串行化)

        不會出現任何併發問題,因爲它是對同一數據的訪問是串行的,非併發訪問的;

        性能最差;

(2)REPEATABLEREAD(可重複讀)

        防止髒讀和不可重複讀;(不能處理幻讀

        性能比SERIALIZABLE好

(3)READCOMMITTED(讀已提交數據)

        防止髒讀;(不能處理不可重複讀、幻讀

        性能比REPEATABLE READ好

(4)READUNCOMMITTED(讀未提交數據)

        可能出現任何事務併發問題

        性能最好

    mysql數據庫默認的事務隔離級別-----repeatable read級別.

    oracle數據默認的事務隔離級別 ----read committed

 

    安全性:serializable> repeatable read > read committed > read uncommitted

    性能 :serializable <repeatable read < read committed < read uncommitted

3.3 事務隔離級別的設置

(1)mysql中設置

    數據庫默認有事務的隔離級別,mysql 中查看與修改事務的隔離級別

        set  session  transaction  isolation  level 隔離級別;設置事務隔離級別

        select  @@tx_isolation;       查詢當前事務隔離級別

(2)jdbc中設置事務隔離級別

        在java.sql.Connection接口中提供

             con. setTransactionIsolation(int level)

        參數可選值如下:

         Connection.TRANSACTION_READ_UNCOMMITTED;

         Connection.TRANSACTION_READ_COMMITTED;

         Connection.TRANSACTION_REPEATABLE_READ;

         Connection.TRANSACTION_SERIALIZABLE。

    (注意,不能使用 Connection.TRANSACTION_NONE,因爲它指定了不受支持的事務。)

4. ThreadLocal簡介

    public classThreadLocal<T>extends Object

        該類提供了線程局部(thread-local) 變量。這些變量不同於它們的普通對應物,因爲訪問某個變量(通過其 get 或 set 方法)的每個線程都有自己的局部變量,它獨立於變量的初始化副本。ThreadLocal 實例通常是類中的 private static 字段,它們希望將狀態與某一個線程(例如,用戶 ID 或事務 ID)相關聯。

    它的底層是使用了一個Map集合

    Map<Thread,Object>

    它的key就是當前的線程對象.

        set(Object obj) 它就相當於 map.put(Thread.currentThread(),obj);

        get()它就相當於 map.get(Thread.currentThread());

 

        ThreadLocal可以理解成是一個Map集合Map<Thread,Object>set方法是向ThreadLocal中存儲數據,那麼當前的key值就是當前線程對象。get方法是從ThreadLocal中獲取數據,它是根據當前線程對象來獲取值。如果我們是在同一個線程中,只要在任意的一個位置存儲了數據,在其它位置上,就可以獲取到這個數據

5. 事務的丟失更新問題(lost update )

5.1 事務丟失更新概述

        兩個或多個事務更新同一行,但這些事務彼此之間都不知道其它事務進行的修改,因此後一個的更改覆蓋了前一個修改。

5.2丟失更新問題的解決方法

(1)悲觀鎖(PessimisticLocking)-------假設丟失更新一定會發生,利用數據庫內部鎖機制,管理事務

            mysql數據庫內部提供的兩種常用鎖機制:共享鎖(讀鎖)和排它鎖(寫鎖),允許一張數據表中數據記錄,添加多個共享鎖,添加共享鎖記錄,對於其他事務可讀不可寫的

            一張數據表中數據記錄,只能添加一個排它鎖,在添加排它鎖的數據不能再添加其他共享鎖和排它鎖的,對於其他事物可讀不可寫的。所有數據記錄修改操作,自動爲數據添加排它鎖

 

        添加共享鎖方式:select* from account lock in share mode ;(讀鎖、共享鎖)

        添加排它鎖方式:select* from account for update; (寫鎖、排它鎖)

 

        鎖必須在事務中添加 ,如果事務結束了 鎖就釋放了

 

        解決丟失更新:事務在修改記錄過程中,鎖定記錄,別的事務無法併發修改。

 

(2)樂觀鎖(Optimistic Locking)-------假設丟失更新不會發生,採用程序中添加版本字段解決丟失更新問題。

        採用記錄的版本字段,來判斷記錄是否修改過-------------- timestamp【通過時間戳字段】

        timestamp 可以自動更新

    create table product (

       id int,

       name varchar(20),

       updatetime timestamp

    );

 

    insert into product values(1,'小米',null);

    update product set name='三星' where id = 1;

 

    timestamp 在插入和修改時都會自動更新爲當前時間

 

    解決丟失更新:在數據表添加版本字段,每次修改過記錄後,版本字段都會更新,如果讀取是版本字段,與修改時版本字段不一致,說明別人進行修改過數據(重改)。

 

事務總結:

1)事務的特性:ACID

2)事務開始邊界與結束邊界:開始邊界(con.setAutoCommit(false)),結束邊界(con.commit()con.rollback());

3)事務的隔離級別: READ_UNCOMMITTEDREAD_COMMITTEDREPEATABLE_READSERIALIZABLE。多個事務併發執行時才需要考慮併發事務。

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章