事務(wù)處理
信息是任何企事業(yè)單位的重要資產(chǎn),任何企業(yè)部門(mén)都包含著信息的流入、流出,任何企業(yè)部門(mén)都控制著某些信息。同時(shí),信息必須在適當(dāng)?shù)臅r(shí)機(jī)傳播給需要的人。而且,信息還需要安全約束,通常根據(jù)信息的類型和內(nèi)容實(shí)施訪問(wèn)控制。為了保證數(shù)據(jù)的安全有效和正確可靠,數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)必須提供統(tǒng)一的數(shù)據(jù)保護(hù)功能。
事務(wù)是現(xiàn)代數(shù)據(jù)庫(kù)理論中的核心概念之一。如果一組處理步驟或者全部發(fā)生或者一步也不執(zhí)行,我們稱該組處理步驟為一個(gè)事務(wù)。當(dāng)所有的步驟像一個(gè)操作一樣被完整地執(zhí)行,我們稱該事務(wù)被提交。由于其中的一部分或多步執(zhí)行失敗,導(dǎo)致沒(méi)有步驟被提交,則事務(wù)必須回滾(回到最初的系統(tǒng)狀態(tài))。事務(wù)必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫(xiě)。事務(wù)的原子性表示事務(wù)執(zhí)行過(guò)程中的任何失敗都將導(dǎo)致事務(wù)所做的任何修改失效。一致性表示當(dāng)事務(wù)執(zhí)行失敗時(shí),所有被該事務(wù)影響的數(shù)據(jù)都應(yīng)該恢復(fù)到事務(wù)執(zhí)行前的狀態(tài)。隔離性表示在事務(wù)執(zhí)行過(guò)程中對(duì)數(shù)據(jù)的修改,在事務(wù)提交之前對(duì)其他事務(wù)不可見(jiàn)。持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。
在下面我們列舉一個(gè)使用SQL Server數(shù)據(jù)庫(kù)進(jìn)行事務(wù)處理的例子。主表是一個(gè)規(guī)章制度信息表(bylaw),主要字段有記錄編號(hào)、標(biāo)題、作者、書(shū)寫(xiě)日期等。兩個(gè)子表分別是附件表(bylaw_affix)和文本信息表(bylaw_content)。表結(jié)構(gòu)見(jiàn)圖1所示。bylaw表的記錄編號(hào)與bylaw_affix表的記錄編號(hào)、bylaw_content表的記錄編號(hào)是對(duì)應(yīng)的,每次對(duì)規(guī)章制度信息的操作也就是對(duì)這三個(gè)表的聯(lián)合操作。例如要?jiǎng)h除規(guī)章制度中的一條記錄,如果不使用事務(wù),就可能會(huì)出現(xiàn)這樣的情況:第一個(gè)表中成功刪除后,數(shù)據(jù)庫(kù)突然出現(xiàn)意外狀況,而第二、三個(gè)表中的操作沒(méi)有完成,這樣,刪除操作并沒(méi)有完成,甚至已經(jīng)破壞數(shù)據(jù)庫(kù)中的數(shù)據(jù)。要避免這種情況,就應(yīng)該使用事務(wù),它的作用是:要么三個(gè)表都操作成功,要么都失敗。換句話說(shuō),就是保持?jǐn)?shù)據(jù)的一致性。所以,為了確保對(duì)數(shù)據(jù)操作的完整和一致,在程序設(shè)計(jì)時(shí)要充分考慮到事務(wù)處理方面的問(wèn)題。
圖1 示例表結(jié)構(gòu)
Java中的事務(wù)處理
一般情況下,J2EE應(yīng)用服務(wù)器支持JDBC事務(wù)、JTA(Java Transaction API)事務(wù)、容器管理事務(wù)。一般情況下,最好不要在程序中同時(shí)使用上述三種事務(wù)類型,比如在JTA事務(wù)中嵌套JDBC事務(wù)。第二方面,事務(wù)要在盡可能短的時(shí)間內(nèi)完成,不要在不同方法中實(shí)現(xiàn)事務(wù)的使用。下面我們列舉兩種事務(wù)處理方式。
1、JavaBean中使用JDBC方式進(jìn)行事務(wù)處理
在JDBC中怎樣將多個(gè)SQL語(yǔ)句組合成一個(gè)事務(wù)呢?在JDBC中,打開(kāi)一個(gè)連接對(duì)象Connection時(shí),缺省是auto-commit模式,每個(gè)SQL語(yǔ)句都被當(dāng)作一個(gè)事務(wù),即每次執(zhí)行一個(gè)語(yǔ)句,都會(huì)自動(dòng)的得到事務(wù)確認(rèn)。為了能將多個(gè)SQL語(yǔ)句組合成一個(gè)事務(wù),要將auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不調(diào)用commit()方法,SQL語(yǔ)句不會(huì)得到事務(wù)確認(rèn)。在最近一次commit()方法調(diào)用之后的所有SQL會(huì)在方法commit()調(diào)用時(shí)得到確認(rèn)。
public int delete(int sID) {
dbc = new DataBaseConnection();
Connection con = dbc.getConnection();
try {
con.setAutoCommit(false);// 更改JDBC事務(wù)的默認(rèn)提交方式
dbc.executeUpdate("delete from bylaw where ID=" + sID);
dbc.executeUpdate("delete from bylaw _content where ID=" + sID);
dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);
con.commit();//提交JDBC事務(wù)
con.setAutoCommit(true);// 恢復(fù)JDBC事務(wù)的默認(rèn)提交方式
dbc.close();
return 1;
}
catch (Exception exc) {
con.rollBack();//回滾JDBC事務(wù)
exc.printStackTrace();
dbc.close();
return -1;
}
}
2、SessionBean中的JTA事務(wù)
JTA 是事務(wù)服務(wù)的 J2EE 解決方案。本質(zhì)上,它是描述事務(wù)接口(比如 UserTransaction 接口,開(kāi)發(fā)人員直接使用該接口或者通過(guò) J2EE 容器使用該接口來(lái)確保業(yè)務(wù)邏輯能夠可靠地運(yùn)行)的 J2EE 模型的一部分。JTA 具有的三個(gè)主要的接口分別是 UserTransaction 接口、TransactionManager 接口和 Transaction 接口。這些接口共享公共的事務(wù)操作,例如 commit() 和 rollback(), 但是也包含特殊的事務(wù)操作,例如 suspend(),resume() 和 enlist(),它們只出現(xiàn)在特定的接口上,以便在實(shí)現(xiàn)中允許一定程度的訪問(wèn)控制。例如,UserTransaction 能夠執(zhí)行事務(wù)劃分和基本的事務(wù)操作,而 TransactionManager 能夠執(zhí)行上下文管理。
應(yīng)用程序可以調(diào)用UserTransaction.begin()方法開(kāi)始一個(gè)事務(wù),該事務(wù)與應(yīng)用程序正在其中運(yùn)行的當(dāng)前線程相關(guān)聯(lián)。底層的事務(wù)管理器實(shí)際處理線程與事務(wù)之間的關(guān)聯(lián)。UserTransaction.commit()方法終止與當(dāng)前線程關(guān)聯(lián)的事務(wù)。UserTransaction.rollback()方法將放棄與當(dāng)前線程關(guān)聯(lián)的當(dāng)前事務(wù)。
public int delete(int sID) {
DataBaseConnection dbc = null;
dbc = new DataBaseConnection();
dbc.getConnection();
UserTransaction transaction = sessionContext.getUserTransaction();//獲得JTA事務(wù)
try {
transaction.begin(); //開(kāi)始JTA事務(wù)
dbc.executeUpdate("delete from bylaw where ID=" + sID);
dbc.executeUpdate("delete from bylaw _content where ID=" + sID);
dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);
transaction.commit(); //提交JTA事務(wù)
dbc.close();
return 1;
}
catch (Exception exc) {
try {
transaction.rollback();//JTA事務(wù)回滾
}
catch (Exception ex) {
//JTA事務(wù)回滾出錯(cuò)處理
ex.printStackTrace();
}
exc.printStackTrace();
dbc.close();
return -1;
}
}
加上的一些心得
1.在數(shù)據(jù)庫(kù)中,開(kāi)啟了事物,如果事物在提交之前發(fā)生了錯(cuò)誤,如果系統(tǒng)回滾了,相應(yīng)的數(shù)據(jù)不會(huì)提交。
2.如果在事物提交了后發(fā)生了異常,即使在catch塊中捕獲了異常,系統(tǒng)也回滾不了。
3.系統(tǒng)在回滾后,其以后的代碼可以繼續(xù)執(zhí)行。
信息是任何企事業(yè)單位的重要資產(chǎn),任何企業(yè)部門(mén)都包含著信息的流入、流出,任何企業(yè)部門(mén)都控制著某些信息。同時(shí),信息必須在適當(dāng)?shù)臅r(shí)機(jī)傳播給需要的人。而且,信息還需要安全約束,通常根據(jù)信息的類型和內(nèi)容實(shí)施訪問(wèn)控制。為了保證數(shù)據(jù)的安全有效和正確可靠,數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)必須提供統(tǒng)一的數(shù)據(jù)保護(hù)功能。
事務(wù)是現(xiàn)代數(shù)據(jù)庫(kù)理論中的核心概念之一。如果一組處理步驟或者全部發(fā)生或者一步也不執(zhí)行,我們稱該組處理步驟為一個(gè)事務(wù)。當(dāng)所有的步驟像一個(gè)操作一樣被完整地執(zhí)行,我們稱該事務(wù)被提交。由于其中的一部分或多步執(zhí)行失敗,導(dǎo)致沒(méi)有步驟被提交,則事務(wù)必須回滾(回到最初的系統(tǒng)狀態(tài))。事務(wù)必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫(xiě)。事務(wù)的原子性表示事務(wù)執(zhí)行過(guò)程中的任何失敗都將導(dǎo)致事務(wù)所做的任何修改失效。一致性表示當(dāng)事務(wù)執(zhí)行失敗時(shí),所有被該事務(wù)影響的數(shù)據(jù)都應(yīng)該恢復(fù)到事務(wù)執(zhí)行前的狀態(tài)。隔離性表示在事務(wù)執(zhí)行過(guò)程中對(duì)數(shù)據(jù)的修改,在事務(wù)提交之前對(duì)其他事務(wù)不可見(jiàn)。持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。
在下面我們列舉一個(gè)使用SQL Server數(shù)據(jù)庫(kù)進(jìn)行事務(wù)處理的例子。主表是一個(gè)規(guī)章制度信息表(bylaw),主要字段有記錄編號(hào)、標(biāo)題、作者、書(shū)寫(xiě)日期等。兩個(gè)子表分別是附件表(bylaw_affix)和文本信息表(bylaw_content)。表結(jié)構(gòu)見(jiàn)圖1所示。bylaw表的記錄編號(hào)與bylaw_affix表的記錄編號(hào)、bylaw_content表的記錄編號(hào)是對(duì)應(yīng)的,每次對(duì)規(guī)章制度信息的操作也就是對(duì)這三個(gè)表的聯(lián)合操作。例如要?jiǎng)h除規(guī)章制度中的一條記錄,如果不使用事務(wù),就可能會(huì)出現(xiàn)這樣的情況:第一個(gè)表中成功刪除后,數(shù)據(jù)庫(kù)突然出現(xiàn)意外狀況,而第二、三個(gè)表中的操作沒(méi)有完成,這樣,刪除操作并沒(méi)有完成,甚至已經(jīng)破壞數(shù)據(jù)庫(kù)中的數(shù)據(jù)。要避免這種情況,就應(yīng)該使用事務(wù),它的作用是:要么三個(gè)表都操作成功,要么都失敗。換句話說(shuō),就是保持?jǐn)?shù)據(jù)的一致性。所以,為了確保對(duì)數(shù)據(jù)操作的完整和一致,在程序設(shè)計(jì)時(shí)要充分考慮到事務(wù)處理方面的問(wèn)題。
圖1 示例表結(jié)構(gòu)
Java中的事務(wù)處理
一般情況下,J2EE應(yīng)用服務(wù)器支持JDBC事務(wù)、JTA(Java Transaction API)事務(wù)、容器管理事務(wù)。一般情況下,最好不要在程序中同時(shí)使用上述三種事務(wù)類型,比如在JTA事務(wù)中嵌套JDBC事務(wù)。第二方面,事務(wù)要在盡可能短的時(shí)間內(nèi)完成,不要在不同方法中實(shí)現(xiàn)事務(wù)的使用。下面我們列舉兩種事務(wù)處理方式。
1、JavaBean中使用JDBC方式進(jìn)行事務(wù)處理
在JDBC中怎樣將多個(gè)SQL語(yǔ)句組合成一個(gè)事務(wù)呢?在JDBC中,打開(kāi)一個(gè)連接對(duì)象Connection時(shí),缺省是auto-commit模式,每個(gè)SQL語(yǔ)句都被當(dāng)作一個(gè)事務(wù),即每次執(zhí)行一個(gè)語(yǔ)句,都會(huì)自動(dòng)的得到事務(wù)確認(rèn)。為了能將多個(gè)SQL語(yǔ)句組合成一個(gè)事務(wù),要將auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不調(diào)用commit()方法,SQL語(yǔ)句不會(huì)得到事務(wù)確認(rèn)。在最近一次commit()方法調(diào)用之后的所有SQL會(huì)在方法commit()調(diào)用時(shí)得到確認(rèn)。
public int delete(int sID) {
dbc = new DataBaseConnection();
Connection con = dbc.getConnection();
try {
con.setAutoCommit(false);// 更改JDBC事務(wù)的默認(rèn)提交方式
dbc.executeUpdate("delete from bylaw where ID=" + sID);
dbc.executeUpdate("delete from bylaw _content where ID=" + sID);
dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);
con.commit();//提交JDBC事務(wù)
con.setAutoCommit(true);// 恢復(fù)JDBC事務(wù)的默認(rèn)提交方式
dbc.close();
return 1;
}
catch (Exception exc) {
con.rollBack();//回滾JDBC事務(wù)
exc.printStackTrace();
dbc.close();
return -1;
}
}
2、SessionBean中的JTA事務(wù)
JTA 是事務(wù)服務(wù)的 J2EE 解決方案。本質(zhì)上,它是描述事務(wù)接口(比如 UserTransaction 接口,開(kāi)發(fā)人員直接使用該接口或者通過(guò) J2EE 容器使用該接口來(lái)確保業(yè)務(wù)邏輯能夠可靠地運(yùn)行)的 J2EE 模型的一部分。JTA 具有的三個(gè)主要的接口分別是 UserTransaction 接口、TransactionManager 接口和 Transaction 接口。這些接口共享公共的事務(wù)操作,例如 commit() 和 rollback(), 但是也包含特殊的事務(wù)操作,例如 suspend(),resume() 和 enlist(),它們只出現(xiàn)在特定的接口上,以便在實(shí)現(xiàn)中允許一定程度的訪問(wèn)控制。例如,UserTransaction 能夠執(zhí)行事務(wù)劃分和基本的事務(wù)操作,而 TransactionManager 能夠執(zhí)行上下文管理。
應(yīng)用程序可以調(diào)用UserTransaction.begin()方法開(kāi)始一個(gè)事務(wù),該事務(wù)與應(yīng)用程序正在其中運(yùn)行的當(dāng)前線程相關(guān)聯(lián)。底層的事務(wù)管理器實(shí)際處理線程與事務(wù)之間的關(guān)聯(lián)。UserTransaction.commit()方法終止與當(dāng)前線程關(guān)聯(lián)的事務(wù)。UserTransaction.rollback()方法將放棄與當(dāng)前線程關(guān)聯(lián)的當(dāng)前事務(wù)。
public int delete(int sID) {
DataBaseConnection dbc = null;
dbc = new DataBaseConnection();
dbc.getConnection();
UserTransaction transaction = sessionContext.getUserTransaction();//獲得JTA事務(wù)
try {
transaction.begin(); //開(kāi)始JTA事務(wù)
dbc.executeUpdate("delete from bylaw where ID=" + sID);
dbc.executeUpdate("delete from bylaw _content where ID=" + sID);
dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);
transaction.commit(); //提交JTA事務(wù)
dbc.close();
return 1;
}
catch (Exception exc) {
try {
transaction.rollback();//JTA事務(wù)回滾
}
catch (Exception ex) {
//JTA事務(wù)回滾出錯(cuò)處理
ex.printStackTrace();
}
exc.printStackTrace();
dbc.close();
return -1;
}
}
加上的一些心得
1.在數(shù)據(jù)庫(kù)中,開(kāi)啟了事物,如果事物在提交之前發(fā)生了錯(cuò)誤,如果系統(tǒng)回滾了,相應(yīng)的數(shù)據(jù)不會(huì)提交。
2.如果在事物提交了后發(fā)生了異常,即使在catch塊中捕獲了異常,系統(tǒng)也回滾不了。
3.系統(tǒng)在回滾后,其以后的代碼可以繼續(xù)執(zhí)行。