日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


「原創(chuàng)」淺談java事務(wù)及隔離級別

 

目錄

  • 一:事務(wù)的定義及作用
  • 二:事務(wù)的四個(gè)特性(ACID)
  • 三:JDBC事務(wù)
  • 四:隔離級別
  • 五、總結(jié)

一:事務(wù)的定義及作用

事務(wù)(Transaction),一般是指要做的或所做的事情。在計(jì)算機(jī)術(shù)語中是指訪問并可能更新數(shù)據(jù)庫中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元(unit)。事務(wù)一般由事務(wù)開始(begin transaction)和事務(wù)結(jié)束(end transaction)之間執(zhí)行的全體操作組成。那么,在平時(shí)的應(yīng)用中,為什么要使用事務(wù)呢?這里筆者想通過一個(gè)簡單的例子來說明事務(wù)的重要性。支付寶是生活中經(jīng)常使用的轉(zhuǎn)賬手段,假如賬戶A要通過支付寶將自己賬戶上的100元轉(zhuǎn)到B賬戶,那么對于A賬戶來說余額就要減去100元,然后在B賬戶里增加100元,此時(shí)算是轉(zhuǎn)賬成功。假如就在A賬戶減去100元時(shí),不巧出現(xiàn)了網(wǎng)絡(luò)故障,B賬戶里還未來得及增加100元,那么整個(gè)轉(zhuǎn)賬業(yè)務(wù)就會出現(xiàn)問題。所以,為了保證業(yè)務(wù)的完整性,就需要通過事務(wù)來控制,將A減少100元和B增加100元放入同一個(gè)事務(wù)中,則該事務(wù)要么執(zhí)行成功,要么執(zhí)行失敗后全部撤銷,以此來保證數(shù)據(jù)的安全。

二:事務(wù)的四個(gè)特性(ACID)

事務(wù)的四個(gè)特性包括原子性(atomicity),一致性(consistency),隔離性(isolation)和持久性(durability)。筆者將通過上文的例子來幫助讀者理解事務(wù)的這四個(gè)特性。1.原子性:事務(wù)是數(shù)據(jù)庫的邏輯工作單位,不可再分。當(dāng)我們把“A減少100和B增加100”加入一個(gè)事務(wù)時(shí),這個(gè)將會成為數(shù)據(jù)庫工作的最小單位,對于A和B數(shù)據(jù)的修改,要么全部成功,要么全部失敗,不會出現(xiàn)某一個(gè)成功另一個(gè)失敗的情況。2.一致性:在事務(wù)處理執(zhí)行前后,數(shù)據(jù)庫是一致的(數(shù)據(jù)庫數(shù)據(jù)完整性約束)。假設(shè)A原來有100元,B原來有0元,那么最初A賬戶和B賬戶一共有100元;當(dāng)事務(wù)結(jié)束時(shí),即轉(zhuǎn)賬成功后,最終A賬戶和B賬戶一共有100元,與最初的值保持不變,是數(shù)據(jù)達(dá)到一致。3.隔離性:每個(gè)事務(wù)都是獨(dú)立的,一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)所影響。例如A給B轉(zhuǎn)賬100元,C給A轉(zhuǎn)賬100元,那么“A減少100元,B增加100元”與“C減少100元,A增加100元”屬于兩個(gè)不同的事務(wù),并且兩個(gè)事務(wù)相對獨(dú)立。4.持久性:事務(wù)處理的結(jié)果能夠被永久保存在數(shù)據(jù)庫中。

三:JDBC事務(wù)

在JDBC中處理事務(wù),都是通過Connection完成的。同一事務(wù)中所有的操作,都在使用同一個(gè)Connection對象。JDBC事務(wù)默認(rèn)是開啟的,并且是默認(rèn)提交。下面是事務(wù)在JAVA中的最基本操作: connection.setAutoCommit(boolean);//設(shè)置是否為自動提交事務(wù),如果true(默認(rèn)值為true)表示自動提交,如果設(shè)置為false,需要手動提交事務(wù)。 connection.commit();//提交事務(wù)。 connection.rollback();//回滾事務(wù)。下面通過示例代碼展示一下:

package cn.itcast.jdbc;
 
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
/**
 * 事務(wù)測試 
 */ 
public class test {
 
 public static void main(String[] args) throws SQLException {
 testTransaction();
 }
 
 static void testTransaction() throws SQLException {
 Connection conn = null;
 Statement st = null;
 ResultSet rs = null;
 Savepoint sp = null;
 try {
 conn = JdbcUtils.getConnection();
 //將事務(wù)設(shè)置成手動提交 
 conn.setAutoCommit(false);
 st = conn.createStatement();
 //id為1的人的Money減100
 String sql = "update user set money=money-100 where id=1";
 st.executeUpdate(sql);
 //設(shè)置回滾點(diǎn)(savepoint) 
 sp = conn.setSavepoint();
 //id為2的人的Money減100
 sql = "update user set money=money-100 where id=2";
 st.executeUpdate(sql);
 sql = "select money from user where id=2";
 rs = st.executeQuery(sql);
 float money = 0.0f;
 if (rs.next()) {
 money = rs.getFloat("money");
 }
 if (money > 300){
 throw new RuntimeException("已經(jīng)超過最大值!");
 }
 //id為2的人的Money加100
 sql = "update user set money=money+100 where id=2";
 st.executeUpdate(sql);
 //提交事務(wù) 
 conn.commit();
 } catch (RuntimeException e) {
 if (conn != null && sp != null) {
 //回滾事務(wù),注意里面的參數(shù)sp即為我們上面設(shè)置的savePoint,如果回滾的話只能回滾到savePoint以下的部分 
 //上面的部分不會得到回滾 
 conn.rollback(sp);
 conn.commit();
 }
 throw e;
 } catch (SQLException e) {
 if (conn != null)
 conn.rollback();
 throw e;
 } finally {
 //釋放資源 
 JdbcUtils.free(rs, st, conn);
 }
 }
}

四:隔離級別

為了應(yīng)對多線程并發(fā)讀取數(shù)據(jù)時(shí)出現(xiàn)的問題,事務(wù)有了“隔離級別”特性,多線程并發(fā)讀取數(shù)據(jù)一般會引發(fā)如下三個(gè)問題:

  1. 臟讀(dirtyreads):指一個(gè)事務(wù)讀取了另外一個(gè)事務(wù)未提交的數(shù)據(jù)。假設(shè)A事務(wù)讀取B事務(wù)尚未提交的數(shù)據(jù),此時(shí)如果B事務(wù)發(fā)生錯(cuò)誤并執(zhí)行回滾操作,那么A事務(wù)讀取到的數(shù)據(jù)就是臟數(shù)據(jù)。 2.不可重復(fù)讀(non-repeatablereads):一個(gè)事務(wù)重新讀取前面讀取過的數(shù)據(jù), 發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)被另一個(gè)已提交的事務(wù)修改過。假如事務(wù)A在執(zhí)行讀取操作,由整個(gè)事務(wù)A比較大,前后讀取同一條數(shù)據(jù)需要經(jīng)歷很長的時(shí)間 。而在事務(wù)A第一次讀取數(shù)據(jù),比如此時(shí)讀取了小明的年齡為20歲,事務(wù)B執(zhí)行更改操作,將小明的年齡更改為30歲,此時(shí)事務(wù)A第二次讀取到小明的年齡時(shí),發(fā)現(xiàn)其年齡是30歲,和之前的數(shù)據(jù)不一樣了,也就是數(shù)據(jù)不重復(fù)了,系統(tǒng)不可以讀取到重復(fù)的數(shù)據(jù),稱為不可重復(fù)讀。3.幻讀(phantomread):是指在一個(gè)事務(wù)內(nèi)讀取到了別的事務(wù)插入的數(shù)據(jù),導(dǎo)致前后讀取不一致。假設(shè)事務(wù)A在執(zhí)行讀取操作,需要兩次統(tǒng)計(jì)數(shù)據(jù)的總量,前一次查詢數(shù)據(jù)總量后,此時(shí)事務(wù)B執(zhí)行了新增數(shù)據(jù)的操作并提交后,這個(gè)時(shí)候事務(wù)A讀取的數(shù)據(jù)總量和之前統(tǒng)計(jì)的不一樣,就像產(chǎn)生了幻覺一樣,平白無故的多了幾條數(shù)據(jù),稱為成為幻讀。會發(fā)現(xiàn),幻讀和不可重復(fù)讀是十分相似的,以致于很多人很難分辨它們,你只需要知道,它們最大的區(qū)別是:不可重復(fù)讀讀取到的是更新(update)數(shù)據(jù),而幻讀讀取到的是插入(insert)數(shù)據(jù)。為了處理上面的讀數(shù)據(jù)問題,java事務(wù)提供了4種隔離級別。
  2. 可串行化(Serializable):可避免臟讀、不可重復(fù)讀、虛讀情況的發(fā)生。
  3. 可重復(fù)讀(Repeatableread):可避免臟讀、不可重復(fù)讀情況的發(fā)生。不可以避免虛讀。3.讀已提交(Readcommitted):可避免臟讀情況發(fā)生。4.讀未提交(Read uncommitted):最低級別,以上情況均無法保證。

1表示有,0表示無

隔離級別臟讀不可重復(fù)讀幻讀讀未提交(Read uncommitted)111讀已提交(Readcommitted)011可重復(fù)讀(Repeatableread)001可串行化(Serializable)000

隔離級別由高到低排列:可串行化>可重復(fù)讀>讀已提交>讀未提交。通常情況下,數(shù)據(jù)庫都有自己的默認(rèn)隔離級別,我們使用spring框架可以指定隔離級別,但是如果指定了數(shù)據(jù)庫不支持的隔離級別,數(shù)據(jù)庫就會使用自己默認(rèn)的。在Oracle數(shù)據(jù)庫中,默認(rèn)隔離級別是Read committed,而另一個(gè)常用數(shù)據(jù)庫MySQL中,默認(rèn)隔離級別是Repeatable read。下面,我們用mysql的例子說明各個(gè)隔離級別的情況:開啟兩個(gè)命令行客戶端分別為A,B;不斷改變A的隔離級別,在B端修改數(shù)據(jù)。實(shí)際步驟同序號。

1.讀未提交(最低的隔離級別):

「原創(chuàng)」淺談java事務(wù)及隔離級別

 


「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1. 讀已提交:
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  
  2. 可重復(fù)讀
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  
「原創(chuàng)」淺談java事務(wù)及隔離級別

 

  1.  

值得一提的是,如果在客戶端A中接著執(zhí)行update num= num + 1 where id = 1,num沒有變成1+1=2,而是步驟(2)中更新過后的num=10來算的,所以是10 + 1 = 11,數(shù)據(jù)的一致性倒是沒有被破壞。可重復(fù)讀的隔離級別下使用了MVCC機(jī)制,select操作不會更新版本號,是快照讀(歷史版本);insert、update和delete會更新版本號,是當(dāng)前讀(當(dāng)前版本)。

4.串行化

「原創(chuàng)」淺談java事務(wù)及隔離級別

 


「原創(chuàng)」淺談java事務(wù)及隔離級別

 

mysql中事務(wù)隔離級別為serializable時(shí)會鎖表,若一個(gè)事務(wù)來查詢同一份數(shù)據(jù)就必須等待,直到前一個(gè)事務(wù)完成并解除鎖定為止,因此不會出現(xiàn)幻讀的情況,這種隔離級別并發(fā)性極低,開發(fā)中很少會用到。

五、總結(jié)

事務(wù)控制是構(gòu)建J2EE應(yīng)用不可缺少的一部分,合理選擇應(yīng)用何種事務(wù)對整個(gè)應(yīng)用系統(tǒng)來說至關(guān)重要。一般說來,在單個(gè)JDBC 連接連接的情況下可以選擇JDBC事務(wù),在跨多個(gè)連接或者數(shù)據(jù)庫情況下,需要選擇使用JTA事務(wù),如果用到了EJB,則可以考慮使用EJB容器事務(wù),有興趣的朋友可以關(guān)注一下。對于隔離級別來說,讀未提交、讀已提交和可重復(fù)讀這三種隔離級別隔離的是行數(shù)據(jù),他們的不同只是對應(yīng)讀、寫之間的鎖定關(guān)系不同而已,讀未提交,事務(wù)進(jìn)行寫操作時(shí)并沒有鎖定禁止讀的動作;讀已提交在進(jìn)行事務(wù)在進(jìn)行寫操作時(shí)鎖定了行數(shù)據(jù),禁止在寫期間讀數(shù)據(jù);而可重復(fù)讀則是在讀期間禁止數(shù)據(jù)的寫;串行化即鎖定整個(gè)表的讀寫。希望讀者能夠合理選擇并使用它們。

分享到:
標(biāo)簽:事務(wù) java
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定