JDBC(四)事務(wù)管理

1.銀行轉(zhuǎn)賬案例

案例:銀行轉(zhuǎn)賬:從張無忌賬戶上給趙敏轉(zhuǎn)1000塊錢.
準(zhǔn)備:account(賬戶表):

id            name(賬號(hào),唯一)           balance(余額)
1             張無忌                    20000
2             趙敏                      0

轉(zhuǎn)賬操作步驟:
①:查詢張無忌的賬戶余額是否大于等于1000.

SELECT * FROM account WHERE  name = '王健林' AND balance >= 100;

余額小于1000 : 溫馨提示:親,你的余額不足.
余額大于等于1000: GOTO 2;
②:從王健林的賬戶余額中減少100.

UPDATE account SET balance = balance - 1000 WHERE name = '王健林';

③:在馬云的賬戶余額中增加100.

UPDATE account SET balance = balance + 1000 WHERE name = '馬云';
public class TransactionTest extends TestCase {

    // 案例:銀行轉(zhuǎn)賬:從王健林賬戶上轉(zhuǎn)100個(gè)億給馬云
    public void testTranscation() throws Exception {

        // 1.查詢王健林賬戶的余額是否大約100億
        String sql = "SELECT * FROM t_account WHERE name =? AND balance >= ?";
        Connection conn = JdbcUtil.getConn();
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setString(1, "王健林");
        ps.setInt(2, 2000);
        ResultSet rs = ps.executeQuery();
        int wBalance = 0;
        if (rs.next()) {
            wBalance = rs.getInt("balance");
            System.out.println(rs.getString("name") + "還有" + wBalance + "的余額");
        } else {
            throw new RuntimeException("余額不足");
        }

        // 2.從王健林的賬戶中余額減少100
        sql = "UPDATE t_account SET balance= ? WHERE name= ?";
        ps = conn.prepareStatement(sql);
        ps.setInt(1, wBalance - 100);
        ps.setString(2, "王健林");
        ps.executeUpdate();

        // 3.查詢馬云的余額
        int mBalance = 0;
        sql = "SELECT * FROM t_account WHERE name =?";
        ps = conn.prepareStatement(sql);
        ps.setString(1, "馬云");
        rs = ps.executeQuery();
        if (rs.next()) {
            mBalance = rs.getInt("balance");
            System.out.println(rs.getString("name") + "還有" + mBalance + "的余額");
        } else {
            throw new RuntimeException("沒有馬云賬戶");
        }

        // 4.給馬云的賬戶余額中增加100
        sql = "UPDATE t_account SET balance= ? WHERE name= ?";
        ps = conn.prepareStatement(sql);
        ps.setInt(1, mBalance + 100);
        ps.setString(2, "馬云");
        ps.executeUpdate();

        // 關(guān)閉資源
        JdbcUtil.close(conn, ps, rs);
    }

}

悲劇的事情來了:當(dāng)程序執(zhí)行到第②步和第③步之間,突然停電了.
使用異常來模擬停電:System.out.println(1/0);


2.JDBC的事務(wù)操作

事務(wù)(Transaction,簡(jiǎn)寫為tx):

  • 在數(shù)據(jù)庫(kù)中,所謂事務(wù)是指一組邏輯操作單元,使數(shù)據(jù)從一種狀態(tài)變換到另一種狀態(tài)疙咸。

  • 為確保數(shù)據(jù)庫(kù)中數(shù)據(jù)的一致性,數(shù)據(jù)的操縱應(yīng)當(dāng)是離散的成組的邏輯單元:
    (1)當(dāng)每個(gè)邏輯操作單元全部完成時(shí),數(shù)據(jù)的一致性可以保持;
    (2)而當(dāng)這個(gè)單元中的一部分操作失敗,整個(gè)事務(wù)應(yīng)全部視為錯(cuò)誤,所有從起始點(diǎn)以后的操作應(yīng)全部回退到開始狀態(tài)芯侥。

  • 事務(wù)的操作:先定義開始一個(gè)事務(wù),然后對(duì)數(shù)據(jù)作修改操作,這時(shí)如果提交(commit),這些修改就永久地保存下來,如果回退(rollback),數(shù)據(jù)庫(kù)管理系統(tǒng)將放棄您所作的所有修改而回到開始事務(wù)時(shí)的狀態(tài)羡洁。

  • 事務(wù):指構(gòu)成單個(gè)邏輯工作單元的操作集合扔役。

  • 事務(wù)處理:保證所有事務(wù)都作為一個(gè)工作單元來執(zhí)行权纤,即使出現(xiàn)了故障,都不能改變這種執(zhí)行方式逼龟。當(dāng)在一個(gè)事務(wù)中執(zhí)行多個(gè)操作時(shí)评凝,要么所有的事務(wù)都被提交(commit),要么整個(gè)事務(wù)回滾(rollback)到最初狀態(tài)腺律。

簡(jiǎn)單講:事務(wù)其實(shí)就是多個(gè)操作,把多個(gè)操作看成是一個(gè)不可分割的整體,整體中的多個(gè)要成功都成功,要失敗都失敗奕短。
在紅樓夢(mèng)中: 一損俱損,就是這個(gè)思想.


事務(wù)的ACID屬性:

1. 原子性(Atomicity):原子在化學(xué)中,是最小單位,不可以再分割了。
原子性是指事務(wù)是一個(gè)不可分割的工作單位匀钧,事務(wù)中的操作要么都發(fā)生翎碑,要么都不發(fā)生。
2. 一致性(Consistency):包裝數(shù)據(jù)的完整性榴捡。
事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另外一個(gè)一致性狀態(tài)杈女。(數(shù)據(jù)不被破壞)
3. 隔離性(Isolation):事務(wù)的隔離性是指一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾朱浴,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的吊圾,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。
4. 持久性(Durability):
持久性是指一個(gè)事務(wù)一旦被提交翰蠢,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就是永久性的项乒,接下來的其他操作和數(shù)據(jù)庫(kù)故障不應(yīng)該對(duì)其有任何影響。


事務(wù)的操作:

事務(wù)成功: 提交事務(wù)(commit),如果事務(wù)不提交,在數(shù)據(jù)庫(kù)中數(shù)據(jù)永遠(yuǎn)都不會(huì)改變;
事務(wù)失斄翰住: 出現(xiàn)異常的時(shí)候,事務(wù)失敗.事務(wù)回滾:rollback(取消之前所有的操作,回到事務(wù)最初的狀態(tài)),釋放鎖資源檀何。


操作事務(wù)的模板:

try{
    取消事務(wù)的自動(dòng)提交機(jī)制,設(shè)置為手動(dòng)提交. connection對(duì)象.setAutoCommit(false);
    操作1
    操作2
    異常
    操作3
    ....
   手動(dòng)提交事務(wù)                          connection對(duì)象.commit();
}catch(Exception e){
   //處理異常
   回滾事務(wù)                              connection對(duì)象.rollback();
}

上面案例的事務(wù)處理

public void testTranscation() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtil.getConn();
            conn.setAutoCommit(false);// 取消事務(wù)的自動(dòng)提交機(jī)制
            String sql = "SELECT * FROM t_account WHERE name =? AND balance >= ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "王健林");
            ps.setInt(2, 2000);
            rs = ps.executeQuery();
            int wBalance = 0;
            if (rs.next()) {
                wBalance = rs.getInt("balance");
                System.out.println(rs.getString("name") + "還有" + wBalance + "的余額");
            } else {
                throw new RuntimeException("余額不足");
            }
            // 2.從王健林的賬戶中余額減少100
            sql = "UPDATE t_account SET balance= ? WHERE name= ?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1, wBalance - 100);
            ps.setString(2, "王健林");
            ps.executeUpdate();

            // 3.查詢馬云的余額
            int mBalance = 0;
            sql = "SELECT * FROM t_account WHERE name =?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, "馬云");
            rs = ps.executeQuery();
            if (rs.next()) {
                mBalance = rs.getInt("balance");
                System.out.println(rs.getString("name") + "還有" + mBalance + "的余額");
            } else {
                throw new RuntimeException("沒有馬云賬戶");
            }
            System.out.println(1 / 0); // 模擬停電
            // 4.給馬云的賬戶余額中增加100
            sql = "UPDATE t_account SET balance= ? WHERE name= ?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1, mBalance + 100);
            ps.setString(2, "馬云");
            ps.executeUpdate();
            conn.commit();//提交事務(wù)
            System.out.println("轉(zhuǎn)賬成功");
        } catch (Exception e) {
            try {
                conn.rollback();   //事務(wù)回滾
                System.out.println("轉(zhuǎn)賬失敗");
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        } finally {
            // 關(guān)閉資源
            JdbcUtil.close(conn, ps, rs);
        }

    }

事務(wù)相關(guān)的:

  • 1.默認(rèn)情況下,事務(wù)在執(zhí)行完DML操作就自動(dòng)提交.
  • 2.查詢操作,其實(shí)是不需要事務(wù)的.但是,一般的,我們?cè)陂_發(fā)中都把查詢放入事務(wù)中.
  • 3.開發(fā)中,代碼完全正確,沒有異常,但是就是數(shù)據(jù)庫(kù)中數(shù)據(jù)不變.
    意識(shí):沒有提交事務(wù).
  • 4.在MySQL中,只有InnoDB存儲(chǔ)引擎支持事務(wù),支持外鍵,MyISAM不支持事務(wù).
  • 5.以后事務(wù)我們不應(yīng)該在DAO層處理,應(yīng)該在service層控制.
  • 6.事務(wù)在講解Hibernate,MyBatis,Spring,項(xiàng)目的時(shí)候都會(huì)再講.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廷支,隨后出現(xiàn)的幾起案子频鉴,更是在濱河造成了極大的恐慌,老刑警劉巖恋拍,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垛孔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡施敢,警方通過查閱死者的電腦和手機(jī)周荐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來僵娃,“玉大人概作,你說我怎么就攤上這事∧梗” “怎么了讯榕?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)匙睹。 經(jīng)常有香客問我瘩扼,道長(zhǎng)谆甜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任集绰,我火速辦了婚禮规辱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栽燕。我一直安慰自己罕袋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布碍岔。 她就那樣靜靜地躺著浴讯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔼啦。 梳的紋絲不亂的頭發(fā)上榆纽,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音捏肢,去河邊找鬼奈籽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸵赫,可吹牛的內(nèi)容都是我干的衣屏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼辩棒,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼狼忱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起一睁,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钻弄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后者吁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窘俺,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年砚偶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了批销。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡染坯,死狀恐怖均芽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情单鹿,我是刑警寧澤掀宋,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響劲妙,放射性物質(zhì)發(fā)生泄漏湃鹊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一镣奋、第九天 我趴在偏房一處隱蔽的房頂上張望币呵。 院中可真熱鬧,春花似錦侨颈、人聲如沸余赢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妻柒。三九已至,卻和暖如春耘分,著一層夾襖步出監(jiān)牢的瞬間举塔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工求泰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留央渣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓拜秧,卻偏偏與公主長(zhǎng)得像痹屹,于是被迫代替她去往敵國(guó)和親章郁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子枉氮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容