【菜鳥學Java】14:使用ThreadLocal對Connection進行封裝
問題背景:
使用JDBC進行開發的時候,每一次的增刪改查都必須和資料庫建立連線,才可以對資料項進行相應的操作。當我們的業務比較複雜的情況下,可能會出現在一個方法中多次的執行增刪改查,這樣的話,在這個方法的執行過程中,就需要與資料庫建立多次的連線,在這種場景中,如何保證在併發執行這個方法的過程中,與資料庫的連線不會混亂,保證這些操作的原子性,就顯得尤為重要了。如何解決這個問題呢?
問題分析:
我能想到的方案有兩個,其一:在這個多次執行增刪改查的方法內,宣告一個區域性變數用於存放資料庫連線物件Connection,這樣在呼叫增刪改查方法的時候,將Connection物件作為引數傳進去,這樣就保證了這些子操作都使用的是同一個連線,從而保證了所有操作的連續性和原子性,不會出現資料庫連線物件混亂使用的情況。
其二:我們仔細想想,其實使用者的每一次請求,都會呼叫程式相應的Servlet,而Servlet是單例項多執行緒的,也就是說每一次的請求程式都啟動一個執行緒為使用者服務,在這個執行緒中會呼叫很多的方法,包括我們上面提到的那個需要和資料庫進行多次連線的複雜方法,由此我們可以這樣想,只要保證在這個執行緒中,我們所使用的資料庫連線物件Connection都是同一個,一樣可以保證這些操作的連續性和原子性。
相比較第一種方案而言,第二種顯然要更好一些,因為第一種需要我們在編寫增刪改查方法時,定義Connection的引數,第二種則不用,直接將Connection進行一下封裝即可。
問題解決:
JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多執行緒程式的併發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多執行緒程式,ThreadLocal並不是一個Thread,而是Thread的區域性變數。我們就使用ThreadLocal這個類來對Connection進行一下簡單的封裝,以滿足我們的需求。程式碼如下:
/**
* 採用ThreadLocal封裝Connection
* @author ljw
*
*/
public class ConnectionManager {
//宣告一個本地執行緒變數,用於存放connection
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();
/**
* 得到Connection
* @return
*/
public static Connection getConnection() {
Connection conn = connectionHolder.get();
//如果在當前執行緒中沒有繫結相應的Connection
if (conn == null) {
try {
JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();
Class.forName(jdbcConfig.getDriverName());
conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());
//將Connection設定到執行緒變數ThreadLocal中
connectionHolder.set(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new ApplicationException("系統錯誤,請聯絡系統管理員");
} catch (SQLException e) {
e.printStackTrace();
throw new ApplicationException("系統錯誤,請聯絡系統管理員");
}
}
return conn;
}
/**
* 關閉連線,只關閉當前執行緒的連線
*/
public static void closeConnection() {
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
//從ThreadLocal中清除Connection
connectionHolder.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Statement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs ) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false); //手動提交
}
}
}catch(SQLException e) {}
}
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
}
小結一下:
我們可以在方法內部進行控制,當然我們也可以線上程中進行控制,同一個執行緒的區域性變數不會影響到另一個執行緒的,Java為我們提供了豐富的類庫去開發各種各樣的程式,把玩這些類可以窺探程式設計樂趣,這就是程式設計的魅力所在。在程式設計中多執行緒的問題很值得研究,本篇文章中只是解決了一個小小的Connection獨立性的問題,還有很多很多的其他問題,需要我們去認識和理解。
相關文章
- 【菜鳥學Java】3:封裝一個分頁類PageBeanJava封裝Bean
- 菜鳥學Java(十七)——Jboss瘦身Java
- 菜鳥學Java(十八)——異常Java
- 菜鳥學Java(二十一)——如何更好的進行單元測試——JUnitJava
- 菜鳥學Java(十六)——Jboss簡介Java
- 菜鳥學Java(十一)——GET與POSTJava
- 【菜鳥學Java】11:Session技術JavaSession
- 【菜鳥學Java】10:Cookie技術JavaCookie
- 【菜鳥學Java】4:Servlet 技術JavaServlet
- 菜鳥教程python 學習進度Python
- 菜鳥學Java(十四)——Java反射機制(一)Java反射
- 菜鳥學Java(十五)——Java反射機制(二)Java反射
- 菜鳥學Java(九)——Servlet的基本配置JavaServlet
- 菜鳥學Java(十)——分頁查詢Java
- vue中對axios進行封裝VueiOS封裝
- java菜鳥入門Java
- 菜鳥學Java(四)——JSP內建物件JavaJS物件
- 【菜鳥學Java】9:使用dom4j解析jdbc.xmlJavaJDBCXML
- 通過JNI對C++進行封裝C++封裝
- 對AlamofireObjectMapper進行二次封裝ObjectAPP封裝
- 菜鳥學Java(二十三)——Java記憶體分析Java記憶體
- 【菜鳥學Java】7:JSP的基本語法JavaJS
- 【菜鳥學Java】2:初識J2EEJava
- 菜鳥初學Java的備忘錄(二) (轉)Java
- 菜鳥初學Java的備忘錄(五) (轉)Java
- 菜鳥初學Java的備忘錄(八) (轉)Java
- 菜鳥初學Java的備忘錄(七) (轉)Java
- 菜鳥初學Java的備忘錄(九) (轉)Java
- 菜鳥初學Java的備忘錄(四) (轉)Java
- 菜鳥初學Java的備忘錄(六) (轉)Java
- 菜鳥初學Java的備忘錄(十) (轉)Java
- 菜鳥初學Java的備忘錄(一) (轉)Java
- 菜鳥初學Java的備忘錄(三) (轉)Java
- IT菜鳥的學習生活
- 菜鳥學Java(六)——簡單驗證碼生成(Java版)Java
- 菜鳥也裝Linux(轉)Linux
- Java多執行緒系列——從菜鳥到入門Java執行緒
- 如何使用SHC對Shell指令碼進行封裝和原始碼隱藏指令碼封裝原始碼