在使用Spring時,很多人可能對Spring中爲什麼DAO和Service對象採用單實例方式很迷惑,這些讀者是這麼認爲的:
DAO對象必須包含一個數據庫的連接Connection,而這個Connection不是線程安全的,所以每個DAO都要包含一個不同的Connection對象實例,這樣一來DAO對象就不能是單實例的了。
上述觀點對了一半。對的是“每個DAO都要包含一個不同的Connection對象實例”這句話,錯的是“DAO對象就不能是單實例”。
其實Spring在實現Service和DAO對象時,使用了ThreadLocal這個類,這個是一切的核心! 如果你不知道什麼事ThreadLocal
Spring使用ThreadLocal解決線程安全問題:
Spring中DAO和Service都是以單實例的bean形式存在,Spring通過ThreadLocal類將有狀態的變量(例如數據庫連接Connection)本地線程化,從而做到多線程狀況下的安全。在一次請求響應的處理線程中, 該線程貫通展示、服務、數據持久化三層,通過ThreadLocal使得所有關聯的對象引用到的都是同一個變量。
參考下面代碼,這個是《Spring3.x企業應用開發實戰中的例子》
-
public class SqlConnection {
-
-
privatestatic ThreadLocal <Connection>connThreadLocal = newThreadLocal<Connection>();
-
publicstatic Connection getConnection() {
-
-
-
if (connThreadLocal.get() == null) {
-
Connection conn = getConnection();
-
connThreadLocal.set(conn);
-
return conn;
-
} else {
-
return connThreadLocal.get();
-
-
}
-
}
-
public voidaddTopic() {
-
-
try {
-
Statement stat = getConnection().createStatement();
-
} catch (SQLException e) {
-
e.printStackTrace();
-
}
-
}
-
}
這個是例子展示了不同線程使用TopicDao時如何使得每個線程都獲得不同的Connection實例副本,同時保持TopicDao本身是單實例。