1. JDBC驅(qū)動(dòng)程序的類(lèi)型
目前比較常見(jiàn)的JDBC驅(qū)動(dòng)程序可分為以下四個(gè)種類(lèi):
(1)JDBC-ODBC橋加ODBC驅(qū)動(dòng)程序
JavaSoft橋產(chǎn)品利用ODBC驅(qū)動(dòng)程序提供JDBC訪問(wèn)。注意,必須將ODBC二進(jìn)制代碼(許多情況下還包括數(shù)據(jù)庫(kù)客戶機(jī)代碼)加載到使用該驅(qū)動(dòng)程序的每個(gè)客戶機(jī)上。因此,這種類(lèi)型的驅(qū)動(dòng)程序最適合于企業(yè)網(wǎng)(這種網(wǎng)絡(luò)上客戶機(jī)的安裝不是主要問(wèn)題),或者是用Java編寫(xiě)的三層結(jié)構(gòu)的應(yīng)用程序服務(wù)器代碼。
(2)本地API
這種類(lèi)型的驅(qū)動(dòng)程序把客戶機(jī)API上的JDBC調(diào)用轉(zhuǎn)換為Oracle、Sybase、Informix、DB2或其它DBMS的調(diào)用。注意,象橋驅(qū)動(dòng)程序一樣,這種類(lèi)型的驅(qū)動(dòng)程序要求將某些二進(jìn)制代碼加載到每臺(tái)客戶機(jī)上。
(3)JDBC網(wǎng)絡(luò)純Java驅(qū)動(dòng)程序
這種驅(qū)動(dòng)程序?qū)DBC轉(zhuǎn)換為與DBMS無(wú)關(guān)的網(wǎng)絡(luò)協(xié)議,之后這種協(xié)議又被某個(gè)服務(wù)器轉(zhuǎn)換為一種DBMS協(xié)議。這種網(wǎng)絡(luò)服務(wù)器中間件能夠?qū)⑺募僇ava客戶機(jī)連接到多種不同的數(shù)據(jù)庫(kù)上。所用的具體協(xié)議取決于提供者。通常,這是最為靈活的JDBC驅(qū)動(dòng)程序。有可能所有這種解決方案的提供者都提供適合于Intranet用的產(chǎn)品。為了使這些產(chǎn)品也支持Internet訪問(wèn),它們必須處理Web所提出的安全性、通過(guò)防火墻的訪問(wèn)等方面的額外要求。幾家提供者正將JDBC驅(qū)動(dòng)程序加到他們現(xiàn)有的數(shù)據(jù)庫(kù)中間件產(chǎn)品中。
(4)本地協(xié)議純Java驅(qū)動(dòng)程序
這種類(lèi)型的驅(qū)動(dòng)程序?qū)DBC調(diào)用直接轉(zhuǎn)換為DBMS所使用的網(wǎng)絡(luò)協(xié)議。這將允許從客戶機(jī)機(jī)器上直接調(diào)用DBMS服務(wù)器,是Intranet訪問(wèn)的一個(gè)很實(shí)用的解決方法。由于許多這樣的協(xié)議都是專(zhuān)用的,因此數(shù)據(jù)庫(kù)提供者自己將是主要來(lái)源,有幾家提供者已在著手做這件事了。
據(jù)專(zhuān)家預(yù)計(jì)第(3)、(4)類(lèi)驅(qū)動(dòng)程序?qū)⒊蔀閺腏DBC訪問(wèn)數(shù)據(jù)庫(kù)的首方法。第(1)、(2)類(lèi)驅(qū)動(dòng)程序在直接的純Java驅(qū)動(dòng)程序還沒(méi)有上市前會(huì)作為過(guò)渡方案來(lái)使用。對(duì)第(1)、(2)類(lèi)驅(qū)動(dòng)程序可能會(huì)有一些變種,這些變種要求有連接器,但通常這些是更加不可取的解決方案。第(3)、(4)類(lèi)驅(qū)動(dòng)程序提供了Java的所有優(yōu)點(diǎn),包括自動(dòng)安裝(例如,通過(guò)使用JDBC驅(qū)動(dòng)程序的appletapplet來(lái)下載該驅(qū)動(dòng)程序)。
2. JDBC編程的步驟
1)第一步:加載驅(qū)動(dòng)程序
//jdbc-odbc驅(qū)動(dòng)
try{
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
加載其他各種不同驅(qū)動(dòng)程序的方法如下:
//sqlserver
Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”);
//mysql
Class.forName(“org.gjt.mm.mysql.Driver”);
//oracle
Class.forName(Oracle.jdbc.driver.OracleDriver);
//Informix
Class.forName(“com.informix.jdbc.IfxDriver”);
//Sybase
Class.forName(“com.sybase.jdbc2.jdbc.SybDriver”);
//AS400
Class.forName(“com.ibm.as400.access.AS400JDBCConnection”);
2)第二步:將“驅(qū)動(dòng)程序”傳遞到DriverManager,然后獲得“連接”。
DriverManager類(lèi)的getConnection(String rul,String user,String password)方法用于建立與某個(gè)數(shù)據(jù)庫(kù)的連接。每個(gè)JDBC驅(qū)動(dòng)程序使用一個(gè)專(zhuān)門(mén)的JDBC URL作為自我標(biāo)識(shí)的一種方法。
JDBC URL的格式為:jdbc:<子協(xié)議名>:<子名稱(chēng)>,子協(xié)議與子名稱(chēng)和JDBC驅(qū)動(dòng)程序有關(guān)。
//建立JDBC-ODBC驅(qū)動(dòng)的連接
try{
String url=”jdbc:odbc:myodbc”;
Connection con=DriverManager.getConnection(url);
//或者
//Connection con=DriverManager.getConnection(url,user,password);;
} catch(SQLException e){
e.printStackTrace();
}
以下是連接各種不同的數(shù)據(jù)庫(kù)的URL編寫(xiě)方法:
//sqlserver
DriverManger.getConnection(“jdbc:Microsoft:sqlserver://主機(jī):端口號(hào);DatabaseName=數(shù)據(jù)庫(kù)名”,”用戶名”,”密碼”)
//mysql
DriverManger.getConnection(“jdbc:mysql://主機(jī):端口號(hào):數(shù)據(jù)庫(kù)名”,”用戶名”,”密碼”)
//oracle
DriverManger.getConnection(“jdbc:Oracle:thin:@主機(jī):端口號(hào):數(shù)據(jù)庫(kù)名”,”用戶名”,”密碼”)
//Informix
DriverManger.getConnection(“jdbc:informix-sqli://主機(jī):端口號(hào)/數(shù)據(jù)庫(kù)名:INFORMIXSERVER=informix服務(wù)名”,”用戶名”,”密碼”)
//Sybase
DriverManger.getConnection(“jdbc:sybase:Tds:主機(jī):端口號(hào)/數(shù)據(jù)庫(kù)名”,”用戶名”,””密碼)
//AS400
DriverManger.getConnection(“jdbc:as400://主機(jī)”,”用戶名”,”密碼”)
3)第三步:創(chuàng)建語(yǔ)句,Statement、PreparedStatement或CallableStatement,并將它們用于更新數(shù)據(jù)庫(kù)或執(zhí)行查詢。
4)第四步:查詢并返回包含有已請(qǐng)求數(shù)據(jù)的ResultSet,該ResuletSet是按類(lèi)檢索的。
5)顯示數(shù)據(jù)或根據(jù)得到的查詢結(jié)果完成業(yè)務(wù)邏輯處理。
6)第六步:最后關(guān)閉ResultSet(結(jié)果集)、Statement(語(yǔ)句對(duì)象)、Conection(數(shù)據(jù)庫(kù)連接)。
3. 數(shù)據(jù)庫(kù)各種連接方式實(shí)例分析
1)通過(guò)ODBC建立與數(shù)據(jù)庫(kù)的連接,創(chuàng)建數(shù)據(jù)源的過(guò)程略掉,數(shù)據(jù)源的名稱(chēng)為myodbc,代碼:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>通過(guò)ODBC建立連接</title>
</head>
<body>

<%
Connection con = null;
try {
// 加載ODBC驅(qū)動(dòng)
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// 通過(guò)驅(qū)動(dòng)管理器(DriverManager)獲得連接
con = DriverManager.getConnection("jdbc:odbc:myodbc",
"sa","");
// 如果連接不成功,就會(huì)出現(xiàn)異常,不會(huì)執(zhí)行下面這個(gè)語(yǔ)句
out.println("<H1>");
out.println("通過(guò)ODBC數(shù)據(jù)源連接數(shù)據(jù)庫(kù)成功!");
out.println("</H1>");
} catch (Exception e) {// 如果出現(xiàn)異常,會(huì)打印堆棧里異常的信息
e.printStackTrace();
} finally {// 用完后,關(guān)閉連接,釋放資源
try {
if (con != null) // 防止出現(xiàn)內(nèi)存泄露
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
2)通過(guò)sqlserver提供驅(qū)動(dòng)程序獲得連接,需要3個(gè)jar文件:msbase.jar、mssqlserver.jar、msutil.jar,設(shè)置class環(huán)境變量,或者配置到WEB中,jar文件部署,和所有的jar文件一樣,想在整個(gè)WEB服務(wù)器(我指Tomcat)中使用,就拷貝到Tomcat 6.0\lib目錄下,若在當(dāng)前WEB應(yīng)用中使用,拷貝到WEB應(yīng)用的WEB-INF\lib目錄下。代碼:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>通過(guò)Sqlserver純驅(qū)動(dòng)程序建立連接</title>
</head>
<body>

<%
Connection con = null;
try {
// 加載SQLSERVER的驅(qū)動(dòng)程序
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
// 通過(guò)驅(qū)動(dòng)來(lái)獲得一個(gè)連接
con = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;"
+ "databasename=pubs", "sa", "");

// 如果連接不成功,就會(huì)出現(xiàn)異常,不會(huì)執(zhí)行下面這個(gè)語(yǔ)句
out.println("<H1>");
out.println("通過(guò)SQLServer純驅(qū)動(dòng)程序連接數(shù)據(jù)庫(kù)成功!<br> con="+con);
out.println("</H1>");
} catch (Exception e) {// 如果出現(xiàn)異常,會(huì)打印堆棧里異常的信息
e.printStackTrace();
} finally {// 用完后,關(guān)閉連接,釋放資源
try {
if (con != null) // 防止出現(xiàn)內(nèi)存泄露
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>

3)通過(guò)Oracle提供驅(qū)動(dòng)程序獲得連接,需要用到一個(gè)classes12.jar文件,配置同上。代碼:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>通過(guò)oracle純驅(qū)動(dòng)程序建立連接</title>
</head>
<body>

<%
Connection con = null;
try {
// 加載ORACLE9i的驅(qū)動(dòng)程序
Class.forName("oracle.jdbc.driver.OracleDriver");
// 獲得連接 oracle數(shù)據(jù)庫(kù)的端口號(hào):1521 數(shù)據(jù)服務(wù)器的名字叫ora921
// 登陸的用戶名為system,密碼為:itjob (默認(rèn)密碼為manager)
con = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:ora921",
"system","itjob");
// 如果連接不成功,就會(huì)出現(xiàn)異常,不會(huì)執(zhí)行下面這個(gè)語(yǔ)句
out.println("<H1>");
out.println("通過(guò)ora921純驅(qū)動(dòng)程序連接數(shù)據(jù)庫(kù)成功!<br> con="+con);
out.println("</H1>");
} catch (Exception e) {// 如果出現(xiàn)異常,會(huì)打印堆棧里異常的信息
e.printStackTrace();
} finally {// 用完后,關(guān)閉連接,釋放資源
try {
if (con != null) // 防止出現(xiàn)內(nèi)存泄露
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
4)通過(guò)數(shù)據(jù)庫(kù)連接池獲得連接,連接池將通過(guò)連接的重用,降低開(kāi)銷(xiāo)。
以oracle數(shù)據(jù)庫(kù)為例,配置Tomcat6.0的連接池。
§將classes12.jar拷到Tomcat 6.0\lib目錄下,并修改Tomcat 6.0\conf目錄下的context.xml文件,在文件的</Context>標(biāo)記前面加上如下代碼:
<WatchedResource>WEB-INF/confweb.xml</WatchedResource>
<Resource name="jdbc/oracleds" auth="Container" type="javax.sql.DataSource" maxActive="100"
maxIdle="30" maxWait="10000" username="scott" password="tiger" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@127.0.0.1:1521:wzz"/>
保存并重啟Tomcat。
§編輯jsp文件pool_connection.jsp,代碼如下:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>通過(guò)數(shù)據(jù)庫(kù)連接池建立連接</title>
</head>
<body>

<%
Connection con = null;
try {
Context context =new InitialContext();
DataSource ds=(DataSource)context.lookup("java:/comp/env/jdbc/oracleds");
con=ds.getConnection();
out.println("<H1>");
out.println("第一次通過(guò)數(shù)據(jù)庫(kù)連接池連接數(shù)據(jù)庫(kù)成功!<br> con="+con);
out.println("</H1>");
//con.close();
con = ds.getConnection();
out.println("<H1>");
out.println("第二次通過(guò)數(shù)據(jù)庫(kù)連接池連接數(shù)據(jù)庫(kù)成功!<br> con="+con);
out.println("</H1>");
con.close();
} catch (Exception e) {// 如果出現(xiàn)異常,會(huì)打印堆棧里異常的信息
e.printStackTrace();
}
%>
</body>
</html>
其中連接數(shù)據(jù)庫(kù)的代碼:
Context context =new InitialContext();
DataSource ds=(DataSource)context.lookup("java:/comp/env/jdbc/oracleds");
con=ds.getConnection();
可以修改為如下代碼:
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/oracleds");
con = ds.getConnection();
3. 使用DDL和DML語(yǔ)言對(duì)數(shù)據(jù)進(jìn)行基本操作
1)創(chuàng)建表并插入、修改數(shù)據(jù),代碼如下:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>創(chuàng)建表并插入及修改數(shù)據(jù)</title>
</head>
<body>

<%
Connection con = null;
try {
// 通過(guò)連接池來(lái)獲得一個(gè)連接
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/sqlserver");
con = ds.getConnection();
// 創(chuàng)建語(yǔ)句對(duì)象
Statement st = con.createStatement();
// 創(chuàng)建表的SQL語(yǔ)句
String sql = "create table student(id int,name char(30),age int)";
// 執(zhí)行完SQL語(yǔ)句的結(jié)果
boolean b = st.execute(sql);
out.println("<h2>創(chuàng)建student表成功!</h2><br>");
// 插入數(shù)據(jù)到student表
sql = "insert into student values(1,'andy',47)"
+ "insert into student values(2,'jacky',53)"
+ "insert into student values(3,'周潤(rùn)發(fā)',51)"
+ "insert into student values(4,'謝賢',60)";
// 執(zhí)行完SQL語(yǔ)句的結(jié)果
b = st.execute(sql);
out.println("<h2>插入數(shù)據(jù)成功!</h2><br>");

// 更新表數(shù)據(jù)
sql = "update student set name='劉德華' where id=1";
int rows = st.executeUpdate(sql);

// 如果更新成功,rows肯定是大于1的值
if (rows > 0)
out.println("<h2>修改數(shù)據(jù)成功!</h2><br>");
else
out.println("<h2>修改數(shù)據(jù)失敗!</h2><br>");

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}

%>
</body>
</html>
2)查詢數(shù)據(jù),代碼如下:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>查詢數(shù)據(jù)庫(kù)數(shù)據(jù)</title>
</head>
<body>

<%
Connection con = null;
try {
// 通過(guò)連接池來(lái)獲得一個(gè)連接
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/sqlserver");
con = ds.getConnection();
Statement st = con.createStatement();
String query = "select id,name from student";

// 獲得一個(gè)結(jié)果集
ResultSet rs = st.executeQuery(query);
// 獲得結(jié)果集的元數(shù)據(jù)(表及相關(guān)的信息)
ResultSetMetaData rsmt = rs.getMetaData();
// 得到結(jié)果集有幾列
int num = rsmt.getColumnCount();
String[] columns = new String[num];
// 列的序號(hào)是從1開(kāi)始的
for (int i = 0; i < num; i++)
columns[i] = rsmt.getColumnName(i + 1);
out.println("<table width='600' border='1'>");
out.println("<tr>");
// 先輸出列名
for (int i = 0; i < num; i++)
out.print("<td>"+columns[i] + "</td>");
// 輸出列名之后換行
out.println("</tr>");
// 取出結(jié)果
while (rs.next()) {
// 輸出每一行的值
out.println("<tr>");
for (int i = 1; i <= num; i++) {
String temp = rs.getString(i);
out.print("<td>"+temp + "</td>");
}
out.println("</tr>");
}
out.println("</table>");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后要關(guān)閉連接,釋放資源
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
3)使用預(yù)編譯語(yǔ)句,代碼如下:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>預(yù)編譯的SQL語(yǔ)句</title>
</head>
<body>

<%
Connection con = null;
try {
// 通過(guò)連接池來(lái)獲得一個(gè)連接
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/sqlserver");
con = ds.getConnection();
// 創(chuàng)建修改表的PrepareStatement SQL語(yǔ)句
String sql = "update student set name=? where id=?";
// 創(chuàng)建預(yù)編譯語(yǔ)句對(duì)象
PreparedStatement pst = con.prepareStatement(sql);
String[] names = new String[] { "梁朝偉", "貝殼汗母", "小羅", "霍元甲" };
for (int i = 0; i < names.length; i++) {
pst.setString(1, names[i]);
pst.setInt(2, i + 1);
pst.executeUpdate();
}
pst.close();
// 打印執(zhí)行完SQL語(yǔ)句的結(jié)果
out.println("<h1>修改后的數(shù)據(jù)庫(kù)結(jié)果</h1>");
Statement st = con.createStatement();
String query = "select id,name from student";

// 獲得一個(gè)結(jié)果集
ResultSet rs = st.executeQuery(query);
// 獲得結(jié)果集的元數(shù)據(jù)(表及相關(guān)的信息)
ResultSetMetaData rsmt = rs.getMetaData();
// 得到結(jié)果集有幾列
int num = rsmt.getColumnCount();
String[] columns = new String[num];
// 列的序號(hào)是從1開(kāi)始的
for (int i = 0; i < num; i++)
columns[i] = rsmt.getColumnName(i + 1);
out.println("<table width='600' border='1'>");
out.println("<tr>");
// 先輸出列名
for (int i = 0; i < num; i++)
out.print("<td>"+columns[i] + "</td>");
// 輸出列名之后換行
out.println("</tr>");
// 取出結(jié)果
while (rs.next()) {
// 輸出每一行的值
out.println("<tr>");
for (int i = 1; i <= num; i++) {
String temp = rs.getString(i);
out.print("<td>"+temp + "</td>");
}
out.println("</tr>");
}
out.println("</table>");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后要關(guān)閉連接,釋放資源
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
4)使用存儲(chǔ)過(guò)程。存儲(chǔ)過(guò)程是用來(lái)封裝一段SQL語(yǔ)句完成一個(gè)完整的業(yè)務(wù)功能,這樣可以帶來(lái)更快的性能和改進(jìn)的安全性。存儲(chǔ)過(guò)程可以支持3種類(lèi)型的參數(shù):IN、OUT、INOUT,這對(duì)于存儲(chǔ)過(guò)程在數(shù)據(jù)庫(kù)內(nèi)部真正能做什么來(lái)說(shuō),帶來(lái)了很大的靈活性。不管存儲(chǔ)過(guò)程是用什么語(yǔ)言編寫(xiě)的,它都能以一種標(biāo)準(zhǔn)的方式從java應(yīng)用程序調(diào)用。首先需要?jiǎng)?chuàng)建一個(gè)CallableStatement對(duì)象,允許三種類(lèi)型的調(diào)用,調(diào)用存儲(chǔ)過(guò)程StudentList為例:
§|call StudentList|:如果過(guò)程不需要參數(shù)。
§|call StudentList(?,?)|:如果過(guò)程需要兩個(gè)參數(shù)。
§|? =call StudentList(?,?)|:如果參數(shù)需要兩個(gè)參數(shù)并返回一個(gè)。
首先要?jiǎng)?chuàng)建存儲(chǔ)過(guò)程,代碼如下:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>創(chuàng)建SQLServer存儲(chǔ)過(guò)程</title>
</head>
<body>

<%
Connection con = null;
try {
// 通過(guò)連接池來(lái)獲得一個(gè)連接
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/sqlserver");
con = ds.getConnection();
Statement stmt = con.createStatement();
// 1.創(chuàng)建存儲(chǔ)過(guò)程show_students
String createProcedure1 = "create procedure show_students " + "as " + "select id, name,age " + "from student " + "order by id";
// 刪除數(shù)據(jù)庫(kù)中存在的同名過(guò)程
stmt.executeUpdate("if exists(select name from sysobjects "
+ "where name='show_students'and type='p') "
+ "drop procedure show_students");
stmt.executeUpdate(createProcedure1);
out.println("<h1>第一個(gè)存儲(chǔ)過(guò)程show_students創(chuàng)建成功</h1><br>");

// 2.創(chuàng)建儲(chǔ)存過(guò)程onestudent
String createProcedure2 = "create procedure onestudent "
+ "@stu_id int = null, " + "@name varchar(20) output, "
+ "@age int output " + "as " + "if @stu_id = null "
+ "BEGIN "
+ " PRINT 'ERROR: You must specify a stu_id value.' "
+ " RETURN "
+ "END "
+
// Get the sales for the specified cof_name and " +
// assign it to the output parameter. " +
"SELECT @name = name, @age = age " + "FROM student "
+ "WHERE id = @stu_id " + "RETURN ";
stmt.executeUpdate("if exists(select name from sysobjects "
+ "where name='onestudent'and type='p') "
+ "drop procedure onestudent");
stmt.executeUpdate(createProcedure2);
out.println("<h1>第二個(gè)存儲(chǔ)過(guò)程onestudent創(chuàng)建成功</h1><br>");

// 3.創(chuàng)建函數(shù)
String createProcedure3 = "CREATE FUNCTION ageofstu "
+
// Input cof_name
"(@stu_name varchar(20)) "
+ "RETURNS int "
+ // return sales
"AS " + "BEGIN " + " DECLARE @age int "
+ " SELECT @age = age " + " FROM student "
+ " WHERE name like @stu_name " + " RETURN @age "
+ "END ";
stmt.executeUpdate("if exists(select name from sysobjects "
+ "where name='ageofstu') "
+ "drop function ageofstu");
stmt.executeUpdate(createProcedure3);
out.println("<h1>函數(shù)ageofstu創(chuàng)建成功</h1><br>");
stmt.close();
//con.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后要關(guān)閉連接,釋放資源
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
調(diào)用存儲(chǔ)過(guò)程:

<%
@ page language="java" contentType="text/html; charset=GBK"%>

<%
@ page import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>調(diào)用SQLServer數(shù)據(jù)庫(kù)存儲(chǔ)過(guò)程</title>
</head>
<body>

<%
Connection con = null;
// 定義調(diào)用存儲(chǔ)過(guò)程和函數(shù)的 SQL 語(yǔ)句
String callSQL1 = "{call show_students}";
String callSQL2 = "{call onestudent(?,?,?)}";
String callSQL3 = "{? = call ageofstu(?)}";
try {
// 通過(guò)連接池來(lái)獲得一個(gè)連接
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/sqlserver");
con = ds.getConnection();
// 調(diào)用第 1 個(gè)存儲(chǔ)過(guò)程
CallableStatement cs = con.prepareCall(callSQL1);
ResultSet rs = cs.executeQuery();
out.println("<h1>第一個(gè)存儲(chǔ)過(guò)程調(diào)用結(jié)果</h1><br>");
while (rs.next()) {
String id = rs.getString(1);
String name = rs.getString(2);
String age = rs.getString(3);
out.println(id + " " + name + " " + age+"<br>");
}
// 調(diào)用第 2 個(gè)存儲(chǔ)過(guò)程
cs = con.prepareCall(callSQL2);
cs.setString(1, "2");
cs.registerOutParameter(2, Types.CHAR);
cs.registerOutParameter(3, Types.INTEGER);
cs.execute();
String name = cs.getString(2);
int age = cs.getInt(3);
out.println("<h1>第二個(gè)存儲(chǔ)過(guò)程調(diào)用結(jié)果</h1><br>");
out.println("This student's name is " + name
+ " and age is " + age+"<br>");
// 調(diào)用函數(shù)
cs = con.prepareCall(callSQL3);
cs.setString(2, "小羅");
cs.registerOutParameter(1, Types.INTEGER);
cs.execute();
age = cs.getInt(1);
out.println("<h1>函數(shù)調(diào)用結(jié)果</h1><br>");
out.println("This student's name is " + age + ".<br>");
cs.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后要關(guān)閉連接,釋放資源
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
%>
</body>
</html>
注意:在調(diào)用存儲(chǔ)過(guò)程或函數(shù)需要使用返回參數(shù)時(shí),須使用Call-ableStatement的registerOutParameter(序號(hào),類(lèi)型)對(duì)返回參數(shù)進(jìn)行注冊(cè)。其中序號(hào)是調(diào)用語(yǔ)句從左至右順序號(hào),且起始位置從1計(jì)數(shù)開(kāi)始。