讓不同的Servlet在一個(gè)Session共享連接_JSP教程
推薦:講解Linux系統(tǒng)下JDK、Tomcat的安裝本文詳細(xì)講解Linux系統(tǒng)下JDK、Tomcat的安裝 Jdk安裝: [root@b home]# ls jdk-1_5_0_12-linux-i586-rpm.bin lost found oracle 1、將jdk進(jìn)行解壓 [root@b home]# ./jdk-1_5_0
==== 問(wèn)題所在 ====
如果要編寫一個(gè)購(gòu)物車,通常需要寫很多個(gè)不同功能的servlet。例如用戶登錄、添加商品、查詢購(gòu)物車、結(jié)帳等。
在這些 servlet 中都需要讀寫數(shù)據(jù)庫(kù)。如果我們?cè)诿總(gè) servlet 中都進(jìn)行連接 -> 讀寫 -> 斷開連接的操作,就會(huì)消耗大量的服務(wù)器資源,不僅程序響應(yīng)速度減緩,而且會(huì)加重服務(wù)器和數(shù)據(jù)庫(kù)的負(fù)擔(dān)。
==== 把希望寄托于 HttpSession ====
如我們所學(xué),Servlet API 提供了一些方法和類來(lái)專門處理短期的會(huì)話跟蹤。網(wǎng)站的每個(gè)用戶都和 javax.servlet.http.HttpSession 對(duì)象有關(guān),servlet使用這個(gè)對(duì)象來(lái)記錄和檢索每個(gè)用戶的信息。
幸運(yùn)的是,我們可以在會(huì)話對(duì)象中存儲(chǔ)任意的 java 對(duì)象。存儲(chǔ)的方法大家都已經(jīng)很熟悉,就是使用 setAttribute()方法。代表數(shù)據(jù)庫(kù)連接的Connection也不例外。
這就為我們讓不同的servlet在一個(gè)session內(nèi)共享鏈接帶來(lái)的希望。
==== 安全問(wèn)題 ====
那么,僅僅像下面這樣做就可以了么?
1、在Servlet1中,向session中設(shè)置一個(gè)屬性:
session.setAttribute("connection", connection);
2、在Servlet2中,取出這個(gè)屬性:
Connection connection = (Connection) session.getAttribute ("connection");
理論上,沒(méi)有問(wèn)題。在 Servlet1 中產(chǎn)生的 Connection 對(duì)象,到了 Servlet2 中可以繼續(xù)使用。
但是如果 Servlet2 不小心改變了 connection 的引用,例如 connection = null; 那么,當(dāng)它再次把這個(gè)connection放入session的屬性當(dāng)中,其它的 servlet 就會(huì)得到一個(gè)指向 null 的 connection!
==== 解決之道 ====
把 connection 直接在 session 中傳來(lái)傳去,看來(lái)不怎么安全。
解決思路是,我們找一個(gè)專門的人來(lái)保管這個(gè) connection,在得到請(qǐng)求的時(shí)候,由這個(gè)人把 connection 的引用返回給調(diào)用者。這樣,即使調(diào)用者不小心把它得到的那份 connection 搞壞了,保管著手里也總還有一個(gè)備份。
相應(yīng)的,在 session 的屬性中,我們不再保存 connection 本身,而是把這個(gè)保管者存進(jìn)去。因?yàn)樗茈S時(shí)給我們一個(gè)可用的 connection。
這個(gè)類的具體寫法是:
public class ConnectionHolder {
public ConnectionHolder(Connection con) {
// 保存連接
this.con = con;
try {
// 禁用自動(dòng)提交,以隔離不同session之間的操作。
con.setAutoCommit(false);
}
catch(SQLException e) {
// 錯(cuò)誤處理代碼
}
}
public Connection getConnection() {
// 通過(guò)這個(gè)getter方法獲取連接
return con;
}
private Connection con = null; // 設(shè)置為私有變量,這很重要,以確保變量安全。
}
==== 使用方法 ====
每個(gè) servlet 在希望取得數(shù)據(jù)庫(kù)連接的時(shí)候,先看看 session 中是否有這個(gè)“保管者”(即上面的ConnectionHolder)。
如果有的話,直接調(diào)用它的get方法,取得數(shù)據(jù)庫(kù)連接。
如果沒(méi)有的話,說(shuō)明這個(gè)session還沒(méi)有連接過(guò)數(shù)據(jù)庫(kù),那么當(dāng)前類就立刻創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,并把這個(gè)連接交給保管者,然后再把保管者放入 session 中,以便后續(xù)的 servlet 使用。
下面是一個(gè)實(shí)例:
1 protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
2
3 // 同步代碼取得數(shù)據(jù)庫(kù)連接
4 synchronized (session) {
5 // 看看這個(gè)持有者是否已經(jīng)在 session 中了
6 ConnectionHolder holder = (ConnectionHolder) session.getAttribute
("servletapp.connection");
7
8 // 如果不在,就創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,并把它交給持有者。
9 if (holder == null) {
10 try {
11 holder = new ConnectionHolder(DriverManager.getConnection(
"Connection URL"));
12 session.setAttribute("servletapp.connection", holder);
13 }
14 catch (SQLException sqle) {
15 // 錯(cuò)誤處理代碼
16 }
17 }
18
19 // 從容器取得實(shí)際連接
20 conn = holder.getConnection();
21 }
.... // 別忘了commit
}
這段代碼看起來(lái)有那么幾行。但實(shí)際上,在每個(gè)session中,只有第一次執(zhí)行的servlet需要進(jìn)行數(shù)據(jù)庫(kù)連接操作,此后的servlet只會(huì)執(zhí)行第4、6、20這三行。
==== 誰(shuí)來(lái)負(fù)責(zé)斷開連接? ====
當(dāng) servlet 們不必再為創(chuàng)建數(shù)據(jù)庫(kù)連接費(fèi)心的時(shí)候,也就沒(méi)有人愿意管關(guān)閉連接這檔子事了。事實(shí)上,更重要的是,他們沒(méi)法管。因?yàn)檫@個(gè)連接是放在 session 中的,而沒(méi)有誰(shuí)能準(zhǔn)確的預(yù)測(cè),一個(gè) session 會(huì)何時(shí)終止。
好在有一種叫做“監(jiān)聽器”(Listener)的東西可以專門管這件事。Listener有很多方法,其中的兩個(gè)方法是:
public void valueBound(HttpSessionBingEvent event);
public void valueUnbound(HttpSessionBingEvent event);
這兩個(gè)方法可以在一個(gè) session 被創(chuàng)建/失效的時(shí)候分別自動(dòng)執(zhí)行。我們就把關(guān)閉連接的代碼放在第二個(gè)方法中,這樣,當(dāng)一個(gè) session 失效的時(shí)候,數(shù)據(jù)庫(kù)連接就會(huì)自動(dòng)關(guān)閉。
要想讓一個(gè)類成為L(zhǎng)istener,只需讓它實(shí)現(xiàn) HttpSessionBindingListener 接口。我們的 connection 是由 ConnectionHolder 這個(gè)類來(lái)保管的,因此最方便的辦法就是把它注冊(cè)成一個(gè)監(jiān)聽器。
具體方法是:
public void valueUnbound(HttpSessionBindingEvent event) {
// 當(dāng)從Session刪除或當(dāng)Session結(jié)束時(shí),關(guān)閉數(shù)據(jù)連接。
try {
if (con != null) {
con.rollback(); // 放棄所有未提交的數(shù)據(jù)
con.close();
}
}
catch (SQLException e) {
// 錯(cuò)誤處理代碼
}
}
==== 完整示例 ====
下面是一個(gè)完整的 ConnectionHolder:
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.sql.Connection;
import java.sql.SQLException;
public class ConnectionHolder implements HttpSessionBindingListener {
public ConnectionHolder(Connection con) {
// 保存連接
this.con = con;
try {
con.setAutoCommit(false);
}
catch(SQLException e) {
// 錯(cuò)誤處理代碼
}
}
public Connection getConnection() {
return con;
}
public void valueBound(HttpSessionBindingEvent event) {
// 當(dāng)增加Session時(shí),什么也不做
}
public void valueUnbound(HttpSessionBindingEvent event) {
// 當(dāng)從Session刪除或當(dāng)Session結(jié)束時(shí),關(guān)閉數(shù)據(jù)連接。
try {
if (con != null) {
con.rollback(); // 放棄所有未發(fā)送數(shù)據(jù)
con.close();
}
}
catch (SQLException e) {
// 錯(cuò)誤處理代碼
}
}
private Connection con = null;
}
分享:Linux系統(tǒng)下兩種自動(dòng)啟動(dòng)Tomcat的方法 有很多辦法可以讓Tomcat在系統(tǒng)啟動(dòng)的時(shí)候自動(dòng)運(yùn)行,我這里介紹兩種方法,一種簡(jiǎn)單,另外一種復(fù)雜而專業(yè)。在介紹這兩個(gè)方法前你應(yīng)該先裝JDK,Tomcat。Tomcat的安裝很簡(jiǎn)單,下載二進(jìn)制壓縮包
- jsp response.sendRedirect不跳轉(zhuǎn)的原因分析及解決
- JSP指令元素(page指令/include指令/taglib指令)復(fù)習(xí)整理
- JSP腳本元素和注釋復(fù)習(xí)總結(jié)示例
- JSP FusionCharts Free顯示圖表 具體實(shí)現(xiàn)
- 網(wǎng)頁(yè)模板:關(guān)于jsp頁(yè)面使用jstl的異常分析
- JSP頁(yè)面中文傳遞參數(shù)使用escape編碼
- 基于jsp:included的使用與jsp:param亂碼的解決方法
- Java Web項(xiàng)目中連接Access數(shù)據(jù)庫(kù)的配置方法
- JDBC連接Access數(shù)據(jù)庫(kù)的幾種方式介紹
- 網(wǎng)站圖片路徑的問(wèn)題:絕對(duì)路徑/虛擬路徑
- (jsp/html)網(wǎng)頁(yè)上嵌入播放器(常用播放器代碼整理)
- jsp下顯示中文文件名及絕對(duì)路徑下的圖片解決方法
JSP教程Rss訂閱編程教程搜索
JSP教程推薦
猜你也喜歡看這些
- Apache Tomcat 5.5部署jsp項(xiàng)目總結(jié)之——jsp亂碼問(wèn)題的解決
- Java:Web實(shí)現(xiàn)定時(shí)任務(wù)的簡(jiǎn)便方法
- 在.jsp中非表單請(qǐng)求action的幾種方式總結(jié)
- JSP程序員成長(zhǎng)之路
- J2ME中的XML語(yǔ)法分析利器KXML
- 在無(wú)線J2ME設(shè)備上實(shí)現(xiàn)HTTP協(xié)議1
- JSP實(shí)例:Java實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能實(shí)例
- Struts構(gòu)架中的Session對(duì)象創(chuàng)建和控制
- struts2中action實(shí)現(xiàn)ModelDriven后無(wú)法返回json的解決方法
- JSP內(nèi)置對(duì)象:Request和Response的簡(jiǎn)單介紹及使用
- 相關(guān)鏈接:
- 教程說(shuō)明:
JSP教程-讓不同的Servlet在一個(gè)Session共享連接
。