您好,登錄后才能下訂單哦!
什么是Java事務(wù)
通常的觀念認(rèn)為,事務(wù)僅與數(shù)據(jù)庫(kù)相關(guān)。
事務(wù)必須服從ISO/IEC所制定的ACID原則。ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫。事務(wù)的原子性表示事務(wù)執(zhí)行過程中的任何失敗都將導(dǎo)致事務(wù)所做的任何修改失效。一致性表示當(dāng)事務(wù)執(zhí)行失敗時(shí),所有被該事務(wù)影響的數(shù)據(jù)都應(yīng)該恢復(fù)到事務(wù)執(zhí)行前的狀態(tài)。隔離性表示在事務(wù)執(zhí)行過程中對(duì)數(shù)據(jù)的修改,在事務(wù)提交之前對(duì)其他事務(wù)不可見。持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。
通俗的理解,事務(wù)是一組原子操作單元,從數(shù)據(jù)庫(kù)角度說(shuō),就是一組SQL指令,要么全部執(zhí)行成功,若因?yàn)槟硞€(gè)原因其中一條指令執(zhí)行有錯(cuò)誤,則撤銷先前執(zhí)行過的所有指令。更簡(jiǎn)答的說(shuō)就是:要么全部執(zhí)行成功,要么撤銷不執(zhí)行。
既然事務(wù)的概念從數(shù)據(jù)庫(kù)而來(lái),那Java事務(wù)是什么?之間有什么聯(lián)系?
實(shí)際上,一個(gè)Java應(yīng)用系統(tǒng),如果要操作數(shù)據(jù)庫(kù),則通過JDBC來(lái)實(shí)現(xiàn)的。增加、修改、刪除都是通過相應(yīng)方法間接來(lái)實(shí)現(xiàn)的,事務(wù)的控制也相應(yīng)轉(zhuǎn)移到Java程序代碼中。因此,數(shù)據(jù)庫(kù)操作的事務(wù)習(xí)慣上就稱為Java事務(wù)。
事務(wù)的特性:
1) 原子性(atomicity):事務(wù)是數(shù)據(jù)庫(kù)的邏輯工作單位,而且是必須是原子工作單位,對(duì)于其數(shù)據(jù)修改,要么全部執(zhí)行,要么全部不執(zhí)行。
2) 一致性(consistency):事務(wù)在完成時(shí),必須是所有的數(shù)據(jù)都保持一致狀態(tài)。在相關(guān)數(shù)據(jù)庫(kù)中,所有規(guī)則都必須應(yīng)用于事務(wù)的修改,以保持所有數(shù)據(jù)的完整性。
3) 隔離性(isolation):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)所影響。
4) 持久性(durability):一個(gè)事務(wù)一旦提交,事物的操作便永久性的保存在DB中。即使此時(shí)再執(zhí)行回滾操作也不能撤消所做的更改。
事務(wù)(Transaction):是并發(fā)控制的單元,是用戶定義的一個(gè)操作序列。這些操作要么都做,要么都不做,是一個(gè)不可分割的工作單位。通過事務(wù),sql server 能將邏輯相關(guān)的一組操作綁定在一起,以便服務(wù)器 保持?jǐn)?shù)據(jù)的完整性。事務(wù)通常是以begin transaction開始,以commit或rollback結(jié)束。Commint表示提交,即提交事務(wù)的所有操作。具體地說(shuō)就是將事務(wù)中所有對(duì)數(shù)據(jù)的更新寫回到磁盤上的物理數(shù)據(jù)庫(kù)中去,事務(wù)正常結(jié)束。Rollback表示回滾,即在事務(wù)運(yùn)行的過程中發(fā)生了某種故障,事務(wù)不能繼續(xù)進(jìn)行,系統(tǒng)將事務(wù)中對(duì)數(shù)據(jù)庫(kù)的所有已完成的操作全部撤消,滾回到事務(wù)開始的狀態(tài)。
自動(dòng)提交事務(wù):每條單獨(dú)的語(yǔ)句都是一個(gè)事務(wù)。每個(gè)語(yǔ)句后都隱含一個(gè)commit。 (默認(rèn))
顯式事務(wù):以begin transaction顯示開始,以commit或rollback結(jié)束。
隱式事務(wù):當(dāng)連接以隱式事務(wù)模式進(jìn)行操作時(shí),sql server數(shù)據(jù)庫(kù)引擎實(shí)例將在提交或回滾當(dāng)前事務(wù)后自動(dòng)啟動(dòng)新事務(wù)。無(wú)須描述事物的開始,只需提交或回滾每個(gè)事務(wù)。但每個(gè)事務(wù)仍以commit或rollback顯式結(jié)束。連接將隱性事務(wù)模式設(shè)置為打開之后,當(dāng)數(shù)據(jù)庫(kù)引擎實(shí)例首次執(zhí)行下列任何語(yǔ)句時(shí),都會(huì)自動(dòng)啟動(dòng)一個(gè)隱式事務(wù):alter table,insert,create,open ,delete,revoke ,drop,select, fetch ,truncate table,grant,update在發(fā)出commit或rollback語(yǔ)句之前,該事務(wù)將一直保持有效。在第一個(gè)事務(wù)被提交或回滾之后,下次當(dāng)連接執(zhí)行以上任何語(yǔ)句時(shí),數(shù)據(jù)庫(kù)引擎實(shí)例都將自動(dòng)啟動(dòng)一個(gè)新事務(wù)。該實(shí)例將不斷地生成隱性事務(wù)鏈,直到隱性事務(wù)模式關(guān)閉為止。
JDBC事務(wù)管理
在使用JDBC的時(shí)候, 如何進(jìn)行事務(wù)的管理。直接看一下代碼
示例代碼
/** * @Title: JDBCTrans.java * @Package com.oscar999.trans * @Description: * @author XM * @date Feb 14, 2017 4:38:27 PM * @version V1.0 */ package com.oscar999.trans; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * @author * */ public class JDBCTrans { public JDBCTrans() { } /** * * @param sHostName * @param sPortNumber * @param sSid * @param userName * @param password * @return * @throws SQLException */ public Connection getConnection(String sHostName, String sPortNumber, String sSid, String userName, String password) throws SQLException { Connection conn = null; String url = getOraclURL(sHostName, sPortNumber, sSid); conn = DriverManager.getConnection(url,userName,password); return conn; } /** * * @param conn * @param sql * @throws SQLException */ public void add(Connection conn, String sql) throws SQLException { Statement stmt = null; try { stmt = conn.createStatement(); stmt.execute(sql); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (stmt != null) stmt.close(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String sHostName = ""; String sPortNumber = ""; String sSid = ""; String userName = ""; String password = ""; sHostName = ""; sPortNumber = ""; sSid = ""; userName = ""; password = ""; try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } JDBCTrans jdbcTrans = new JDBCTrans(); Connection conn = null; try { conn = jdbcTrans.getConnection(sHostName, sPortNumber, sSid, userName, password); conn.setAutoCommit(false);// can't insert, update //1. add SQL String addSQL = "insert into TEST_TABLE values('name1','value1')"; jdbcTrans.add(conn,addSQL); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { /*if (conn != null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }*/ } } private String getOraclURL(String sHostName, String sPortNumber, String sSid) { String url = "jdbc:oracle:thin:@" + sHostName + ":" + sPortNumber + ":" + sSid; return url; } }
針對(duì)以上代碼, 說(shuō)明如下:
以上代碼有幾點(diǎn)說(shuō)明的部分:
1. conn.setAutoCommit(false)
執(zhí)行之后不提交事務(wù)。
對(duì)于Select沒有影響, 但對(duì)于Insert和Update的話, 沒有提交數(shù)據(jù)就不會(huì)被修改
2. conn.close();
關(guān)閉Connection的代碼有被Mark掉, 是想呈現(xiàn)conn.setAutoCommit(false)
的效果。
原因是在 Connection Close的時(shí)候會(huì)執(zhí)行一次Commit.
而如果Connection是在應(yīng)用服務(wù)器中使用連接池的話, Connection就不會(huì)被Close, 也就不會(huì)執(zhí)行Commit.
3. setAutoCommit(false)
用法大多數(shù)是在要執(zhí)行多條語(yǔ)句才提交。
所以針對(duì)以上第三點(diǎn), 更接近實(shí)際的狀況的代碼如示例代碼2
示例代碼2
/** * @Title: JDBCTrans.java * @Package com.oscar999.trans * @Description: * @author XM * @date Feb 14, 2017 4:38:27 PM * @version V1.0 */ package com.oscar999.trans; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; /** * @author * */ public class JDBCTrans { public JDBCTrans() { } /** * * @param sHostName * @param sPortNumber * @param sSid * @param userName * @param password * @return * @throws SQLException */ public Connection getConnection(String sHostName, String sPortNumber, String sSid, String userName, String password) throws SQLException { Connection conn = null; String url = getOraclURL(sHostName, sPortNumber, sSid); conn = DriverManager.getConnection(url, userName, password); return conn; } /** * * @param conn * @param sql * @throws SQLException */ public void add(Connection conn, String sql) throws SQLException { Statement stmt = null; try { stmt = conn.createStatement(); stmt.execute(sql); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (stmt != null) stmt.close(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String sHostName = ""; String sPortNumber = ""; String sSid = ""; String userName = ""; String password = ""; sHostName = ""; sPortNumber = ""; sSid = ""; userName = ""; password = ""; try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (ClassNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } JDBCTrans jdbcTrans = new JDBCTrans(); Connection conn = null; try { conn = jdbcTrans.getConnection(sHostName, sPortNumber, sSid, userName, password); conn.setAutoCommit(false);// can't insert, update // 1. add SQL 1 String addSQL = "insert into TEST_TABLE values('name1','value1')"; jdbcTrans.add(conn, addSQL); //2. add SQL 2 addSQL = "insert into TEST_TABLE values('name2','value2')"; jdbcTrans.add(conn, addSQL); conn.commit(); } catch (SQLException e) { // TODO Auto-generated catch block if(conn!=null){ try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } e.printStackTrace(); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } private String getOraclURL(String sHostName, String sPortNumber, String sSid) { String url = "jdbc:oracle:thin:@" + sHostName + ":" + sPortNumber + ":" + sSid; return url; } }
這里需要說(shuō)明的是: conn.rollback();
只要執(zhí)行有異常,就要rollback , 這一步必不可少
如果沒有在執(zhí)行出現(xiàn)異常的時(shí)候進(jìn)行回滾。如果在執(zhí)行第一條語(yǔ)句之后出現(xiàn)異常,con既沒有提交也沒有回滾,表就會(huì)被鎖住(如果oracle數(shù)據(jù)庫(kù)就是行鎖),而這個(gè)鎖卻沒有機(jī)會(huì)釋放。
可能在執(zhí)行con.close()
的時(shí)候會(huì)釋放鎖,但還是如果應(yīng)用服務(wù)器使用了數(shù)據(jù)庫(kù)連接池,連接不會(huì)被斷開。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家學(xué)習(xí)或者使用java能帶來(lái)一定的幫助,如果有疑問大家可以留言交流,謝謝大家對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。