【轉】JDBC事務控制管理

來源:互聯網
上載者:User

標籤:blog   http   io   os   ar   使用   java   for   sp   

轉載聲明:本文轉載自csdn部落格,URL=http://blog.csdn.net/caomiao2006/article/details/22412755

1、事務

(1)事務的概念

事務指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。

例如:A——B轉帳,對應於如下兩條sql語句

update account set money=money-100 where name=‘a’; 

update account set money=money+100 where name=‘b’;

資料庫預設事務是自動認可的,也就是發一條sql它就執行一條。如果想多條sql放在一個事務中執行,則需要使用如下語句。

(2)資料庫開啟事務命令

方式一:利用SQL語句管理事務

start transaction;--開啟事務,這條語句之後的sql語句將處在一個事務當中,這些sql語句並不會立即執行

Commit--提交事務,一旦提交事務,事務中的所有sql語句才會執行。

Rollback -- 復原事務,將之前所有的sql取消。

 

方式二:在資料庫中存在一個自動認可變數,通過show variables like ‘%commit%‘-----autocommit 值是on,說明開啟了事務自動認可。

可以 set autocommint = off(set autocommint=0),關閉自動認可,此時輸入的sql語句就不會自動認可了,需要手動roolback或commit

2、使用事務

(1)當Jdbc程式向資料庫獲得一個Connection對象時,預設情況下這個Connection對象會自動向資料庫提交在它上面發送的SQL語句。若想關閉這種預設提交方式,讓多條SQL在一個事務中執行,可使用下列語句:

(2)JDBC控制事務語句

Connection.setAutoCommit(false); //  相當於start transaction

Connection.rollback();  rollback

Connection.commit();  commit

3、示範銀行轉帳案例

(1)在JDBC代碼中使如下轉帳操作在同一事務中執行。

  update from account set money=money-100 where name=‘a’;

  update from account set money=money+100 where name=‘b’;

(2)設定交易回復點

Savepoint sp = conn.setSavepoint();

Conn.rollback(sp);

Conn.commit();   //復原後必須要提交

package com.itheima.transaction;

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.sql.Savepoint;

 

import org.junit.Test;

 

import com.itheima.util.DaoUtil;

 

public class Demo1 {

@Test

public void test1(){

Connection conn = null;

PreparedStatement ps1 = null;

PreparedStatement ps2 = null;

Savepoint sp = null;

try{

Class.forName("com.mysql.jdbc.Driver");

conn = DriverManager.getConnection("jdbc:mysql:///day11", "root", "root");

conn.setAutoCommit(false);

 

ps1 = conn.prepareStatement("update account set money = money+100 where name=?");

ps1.setString(1, "b");

ps1.executeUpdate();

 

//int i = 1/0;

 

ps2 = conn.prepareStatement("update account set money = money-100 where name=?");

ps2.setString(1, "a");

ps2.executeUpdate();

 

sp = conn.setSavepoint();

//-----------------------------------

ps1 = conn.prepareStatement("update account set money = money+100 where name=?");

ps1.setString(1, "b");

ps1.executeUpdate();

 

int i = 1/0;

 

ps2 = conn.prepareStatement("update account set money = money-100 where name=?");

ps2.setString(1, "a");

ps2.executeUpdate();

 

conn.commit();

 

}catch (Exception e) {

e.printStackTrace();

try {

if(sp !=null){

conn.rollback(sp);

conn.commit();

}else{

conn.rollback();

}

} catch (SQLException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

}finally{

DaoUtil.close(conn, ps1, null);

DaoUtil.close(conn, ps2, null);

}

}

}

 

 

JDBC API支援事務對資料庫的加鎖,並且提供了5種操作支援,2種加鎖密度。

5種加鎖支援為:

static int TRANSACTION_NONE = 0;

static int TRANSACTION_READ_UNCOMMITTED = 1;

static int TRANSACTION_READ_COMMITTED = 2;

static int TRANSACTION_REPEATABLE_READ = 4;

static int TRANSACTION_SERIALIZABLE = 8;

具體的說明見表4-2。

2種加鎖密度:

最後一項為表加鎖,其餘3~4項為行加鎖。

 

JDBC根據資料庫提供的預設值來設定事務支援及其加鎖,當然,也可以手工設定:

setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);

可以查看資料庫的當前設定:

getTransactionIsolation ()

需要注意的是,在進行手動設定時,資料庫及其驅動程式必須得支援相應的事務操作操作才行。

上述設定隨著值的增加,其事務的獨立性增加,更能有效地防止事務操作之間的衝突,同時也增加了加鎖的開銷,降低了使用者之間訪問資料庫的並發性,程式的運行效率也會隨之降低。因此得平衡程式運行效率和資料一致性之間的衝突。一般來說,對於只涉及到資料庫的查詢操作時,可以採用TRANSACTION_READ_UNCOMMITTED方式;對於資料查詢遠多於更新的操作,可以採用TRANSACTION_READ_COMMITTED方式;對於更新操作較多的,可以採用TRANSACTION_REPEATABLE_READ;在資料一致性要求更高的場合再考慮最後一項,由於涉及到表加鎖,因此會對程式運行效率產生較大的影響。

另外,在Oracle中資料庫驅動對交易處理的預設值是TRANSACTION_NONE,即不支援事務操作,所以需要在程式中手動進行設定。總之,JDBC提供的對資料庫事務操作的支援是比較完整的,通過事務操作可以提高程式的運行效率,保持資料的一致性。

 

4、事務的特性(ACID)

(1)原子性(Atomicity)
原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。 

(2)一致性(Consistency)
事務前後資料的完整性必須保持一致。

(3)隔離性(Isolation)
事務的隔離性是指多個使用者並發訪問資料庫時,一個使用者的事務不能被其它使用者的事務所幹擾,多個並發事務之間資料要相互隔離。

(4)持久性(Durability)
持久性是指一個事務一旦被提交,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響

5、事務的隔離等級

(1)多個線程開啟各自事務操作資料庫中資料時,資料庫系統要負責隔離操作,以保證各個線程在擷取資料時的準確性。

(2)如果不考慮隔離性,可能會引發如下問題:

 

髒讀(dirty reads) 

一個事務讀取了另一個未提交的並行事務寫的資料。 

不可重複讀取(non-repeatable reads) 

一個事務重新讀取前面讀取過的資料, 發現該資料已經被另一個已提交的事務修改過。 

幻讀(phantom read) 

一個事務重新執行一個查詢,返回一套符合查詢條件的行, 發現這些行因為其他最近提交的事務而發生了改變。

6、事務的隔離性

(1)髒讀:

指一個事務讀取了另外一個事務未提交的資料。

這是非常危險的,假設A向B轉帳100元,對應sql語句如下所示

1.update account set money=money+100 while name=‘b’;

2.update account set money=money-100 while name=‘a’;

當第1條sql執行完,第2條還沒執行(A未提交時),如果此時B查詢自己的帳戶,就會發現自己多了100元錢。如果A等B走後再復原,B就會損失100元。

        a 1000

b 1000

 

a:

start transaction;

update account set money=money-100 where name=‘a‘;

update account set money=money+100 where name=‘b‘;

 

 

b:

start transaction;

select * from account where name=‘b‘;

 

a:

rollback;

 

b:

strat transaction;

select * from account where name=‘b‘;

(2)不可重複讀取:

在一個事務內讀取表中的某一行資料,多次讀取結果不同。

例如銀行想查詢A帳戶餘額,第一次查詢A帳戶為200元,此時A向帳戶存了100元並提交了,銀行接著又進行了一次查詢,此時A帳戶為300元了。銀行兩次查詢不一致,可能就會很困惑,不知道哪次查詢是準的。

和髒讀的區別是,髒讀是讀取前一事務未提交的髒資料,不可重複讀取是重新讀取了前一事務已提交的資料。

很多人認為這種情況就對了,無須困惑,當然是後面的為準。我們可以考慮這樣一種情況,比如銀行程式需要將查詢結果分別輸出到電腦螢幕和寫到檔案中,結果在一個事務中針對輸出的目的地,進行的兩次查詢不一致,導致檔案和螢幕中的結果不一致,銀行工作人員就不知道以哪個為準了。

        a 1000

b 1000

 

 

start transaction;

select sum(money) from account; ---- 總存款:2000

select count(*) from account; ---- 總賬戶數:2

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

b:

start transaction;

update account set money = money-1000 where name=‘b‘;

commit;

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

select avg(money) from account; ---- 賬戶平均金額:500

 

 

(3)虛讀(幻讀)

是指在一個事務內讀取到了別的事務插入的資料,導致前後讀取不一致。

如丙存款100元未提交,這時銀行做報表統計account表中所有使用者的總額為500元,然後丙提交了,這時銀行再統計發現帳戶為600元了,造成虛讀同樣會使銀行不知所措,到底以哪個為準。

            a 1000

b 1000

c 1000

start transaction;

select sum(money) from account; ---- 總存款:2000

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

c:

start transaction;

insert into account values(null,‘c‘,1000);

commit;

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

select count(*) from account; ---- 總賬戶數:3

7、事務隔離性的設定語句

資料庫共定義了四種隔離等級:

Serializable:可避免髒讀、不可重複讀取、虛讀情況的發生。(序列化)

Repeatable read:可避免髒讀、不可重複讀取情況的發生。(可重複讀)不可以避免虛讀

Read committed:可避免髒讀情況發生(讀已提交)

Read uncommitted:最低層級,以上情況均無法保證。(讀未提交)

set [global/session]  transaction isolation level 設定交易隔離等級

select @@tx_isolation查詢當前交易隔離等級

安全性來說:Serializable>Repeatable read>Read committed>Read uncommitted

效率來說:Serializable<Repeatable read<Read committed<Read uncommitted

通常來說,一般的應用都會選擇Repeatable read或Read committed作為資料庫隔離等級來使用。

mysql預設的資料庫隔離等級為:REPEATABLE-READ

如何查詢當前資料庫的隔離等級?select @@tx_isolation;

如何設定當前資料庫的隔離等級?set [global/session] transaction isolation level ...;

~此種方式設定的隔離等級只對當前串連起作用。

set transaction isolation level read uncommitted;

set session transaction isolation level read uncommitted;

~此種方式設定的隔離等級是設定資料庫預設的隔離等級

set global transaction isolation level read uncommitted;

 

8、事務的丟失更新問題(lost update )

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

(2)共用鎖定:共用鎖定和共用鎖定可以共存。共用鎖定和獨佔鎖定不能共存。在Serializable隔離等級下一個事務進行查詢操作將會加上共用鎖定。

(3)獨佔鎖定:獨佔鎖定和所有鎖都不能共存。無論什麼隔離等級執行增刪改操作時,會加上獨佔鎖定

(4).資料庫設計為Serializable隔離等級,就可以防止更新丟失問題。

 樂觀鎖和悲觀鎖並不是資料庫中真實存在的鎖,是我們如何利用共用和獨佔鎖定解決更新丟失問題的兩種解決方案,體現了人們看待事務的態度:

悲觀鎖:悲觀的認為大部分情況下進行操作都會出現更新丟失問題。

在每次進行查詢的時候,都手動的加上一個獨佔鎖定。

select * from table lock in share mode(讀鎖、共用鎖定)

            select * from table for update (寫鎖、排它鎖)

樂觀鎖:樂觀的認為大部分的情況下都不會有更新丟失問題。通過時間戳記欄位,

在表中設計一個版本欄位version,當每次對資料庫中的資料進行修改操作時,版本號碼都要進行增加。

(5)如果我的程式修改比較少查詢比較多:樂觀鎖

如果我的程式查詢比較少修改比較多:悲觀鎖

【轉】JDBC事務控制管理

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.