Java事務(wù)管理學(xué)習(xí)之JDBC詳解
什么是Java事務(wù)
通常的觀念認(rèn)為,事務(wù)僅與數(shù)據(jù)庫相關(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í)行過程中對數(shù)據(jù)的修改,在事務(wù)提交之前對其他事務(wù)不可見。持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。
通俗的理解,事務(wù)是一組原子操作單元,從數(shù)據(jù)庫角度說,就是一組SQL指令,要么全部執(zhí)行成功,若因?yàn)槟硞€(gè)原因其中一條指令執(zhí)行有錯(cuò)誤,則撤銷先前執(zhí)行過的所有指令。更簡答的說就是:要么全部執(zhí)行成功,要么撤銷不執(zhí)行。
既然事務(wù)的概念從數(shù)據(jù)庫而來,那Java事務(wù)是什么?之間有什么聯(lián)系?
實(shí)際上,一個(gè)Java應(yīng)用系統(tǒng),如果要操作數(shù)據(jù)庫,則通過JDBC來實(shí)現(xiàn)的。增加、修改、刪除都是通過相應(yīng)方法間接來實(shí)現(xiàn)的,事務(wù)的控制也相應(yīng)轉(zhuǎn)移到Java程序代碼中。因此,數(shù)據(jù)庫操作的事務(wù)習(xí)慣上就稱為Java事務(wù)。
事務(wù)的特性:
1) 原子性(atomicity):事務(wù)是數(shù)據(jù)庫的邏輯工作單位,而且是必須是原子工作單位,對于其數(shù)據(jù)修改,要么全部執(zhí)行,要么全部不執(zhí)行。
2) 一致性(consistency):事務(wù)在完成時(shí),必須是所有的數(shù)據(jù)都保持一致狀態(tài)。在相關(guān)數(shù)據(jù)庫中,所有規(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ù)的所有操作。具體地說就是將事務(wù)中所有對數(shù)據(jù)的更新寫回到磁盤上的物理數(shù)據(jù)庫中去,事務(wù)正常結(jié)束。Rollback表示回滾,即在事務(wù)運(yùn)行的過程中發(fā)生了某種故障,事務(wù)不能繼續(xù)進(jìn)行,系統(tǒng)將事務(wù)中對數(shù)據(jù)庫的所有已完成的操作全部撤消,滾回到事務(wù)開始的狀態(tài)。
自動(dòng)提交事務(wù):每條單獨(dú)的語句都是一個(gè)事務(wù)。每個(gè)語句后都隱含一個(gè)commit。 (默認(rèn))
顯式事務(wù):以begin transaction顯示開始,以commit或rollback結(jié)束。
隱式事務(wù):當(dāng)連接以隱式事務(wù)模式進(jìn)行操作時(shí),sql server數(shù)據(jù)庫引擎實(shí)例將在提交或回滾當(dāng)前事務(wù)后自動(dòng)啟動(dòng)新事務(wù)。無須描述事物的開始,只需提交或回滾每個(gè)事務(wù)。但每個(gè)事務(wù)仍以commit或rollback顯式結(jié)束。連接將隱性事務(wù)模式設(shè)置為打開之后,當(dāng)數(shù)據(jù)庫引擎實(shí)例首次執(zhí)行下列任何語句時(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語句之前,該事務(wù)將一直保持有效。在第一個(gè)事務(wù)被提交或回滾之后,下次當(dāng)連接執(zhí)行以上任何語句時(shí),數(shù)據(jù)庫引擎實(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;
}
}
針對以上代碼, 說明如下:
以上代碼有幾點(diǎn)說明的部分:
1. conn.setAutoCommit(false) 執(zhí)行之后不提交事務(wù)。
對于Select沒有影響, 但對于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í)行多條語句才提交。
所以針對以上第三點(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;
}
}
這里需要說明的是: conn.rollback();
只要執(zhí)行有異常,就要rollback , 這一步必不可少
如果沒有在執(zhí)行出現(xiàn)異常的時(shí)候進(jìn)行回滾。如果在執(zhí)行第一條語句之后出現(xiàn)異常,con既沒有提交也沒有回滾,表就會(huì)被鎖住(如果oracle數(shù)據(jù)庫就是行鎖),而這個(gè)鎖卻沒有機(jī)會(huì)釋放。
可能在執(zhí)行con.close()的時(shí)候會(huì)釋放鎖,但還是如果應(yīng)用服務(wù)器使用了數(shù)據(jù)庫連接池,連接不會(huì)被斷開。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家學(xué)習(xí)或者使用java能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
本地MinIO存儲(chǔ)服務(wù)Java遠(yuǎn)程調(diào)用上傳文件的操作過程
MinIO是一款高性能、分布式的對象存儲(chǔ)系統(tǒng),它可以100%的運(yùn)行在標(biāo)準(zhǔn)硬件上,即X86等低成本機(jī)器也能夠很好的運(yùn)行MinIO,這篇文章主要介紹了本地MinIO存儲(chǔ)服務(wù)Java遠(yuǎn)程調(diào)用上傳文件的操作過程,需要的朋友可以參考下2023-11-11
MybatisPlus查詢條件為空字符串或null問題及解決
這篇文章主要介紹了MybatisPlus查詢條件為空字符串或null問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
SpringBoot構(gòu)建RESTful API的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot構(gòu)建RESTful API的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
JAVA純代碼導(dǎo)出PDF文件實(shí)現(xiàn)方式
本文介紹了作者通過突發(fā)奇想發(fā)布了生成PDF的博客,最初,作者通過將Word文件轉(zhuǎn)換為PDF文件實(shí)現(xiàn)導(dǎo)出PDF功能,但效果不盡如人意,后來,作者嘗試直接生成PDF文件,并修復(fù)了生成PDF時(shí)出現(xiàn)的小瑕疵,通過導(dǎo)入依賴、下載接口和下載方法的實(shí)現(xiàn)2025-01-01
Java volatile 關(guān)鍵字介紹與使用示例詳解
這篇文章詳細(xì)介紹了Java中的volatile關(guān)鍵字,包括它的核心特性、如何保證變量的可見性和有序性,以及它在解決多線程問題中的局限性,文章通過示例展示了如何在實(shí)際編程中使用volatile,并解釋了如何通過其他同步機(jī)制來彌補(bǔ)volatile的不足,感興趣的朋友一起看看吧2025-01-01
Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法示例
這篇文章主要給大家介紹了關(guān)于Java處理時(shí)間格式CST和GMT轉(zhuǎn)換方法的相關(guān)資料,相信很多小伙伴在時(shí)間格式轉(zhuǎn)換的時(shí)候非常頭疼,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
java實(shí)現(xiàn)的日期時(shí)間轉(zhuǎn)換工具類完整示例
這篇文章主要介紹了java實(shí)現(xiàn)的日期時(shí)間轉(zhuǎn)換工具類,結(jié)合完整實(shí)例形式分析了java針對日期時(shí)間常見的轉(zhuǎn)換、計(jì)算、格式化等相關(guān)操作與封裝技巧,需要的朋友可以參考下2019-10-10
Java執(zhí)行shell命令的實(shí)現(xiàn)
本文主要介紹了Java執(zhí)行shell命令的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01

