最近好久沒上過BLOG了,前段時(shí)間實(shí)在是很忙啊。以前兩年半的時(shí)間都沒這么忙過呢~~~
今天上網(wǎng)看到一篇文章就轉(zhuǎn)過來,大家一起分享下。前些時(shí)間我在研究JSP中的數(shù)據(jù)庫連接,費(fèi)了好大的勁,做了好多天,終于連接上了,辛苦啊,先喝杯酒慶祝一下,CHEERS.................現(xiàn)在就轉(zhuǎn)帖了
[轉(zhuǎn)]
二,JDBC?主要接口:
java.sql.DriverManager類用于處理驅(qū)動(dòng)程序的調(diào)入并且對(duì)新的數(shù)據(jù)庫連接提供支持。
java.sql.Connection,指應(yīng)用程序與特定數(shù)據(jù)庫的連接。
java.sql.Statement,用于一般sql語句的執(zhí)行(可以是查詢、更新甚至可以創(chuàng)建數(shù)據(jù)庫的執(zhí)行過程)
java.sql.ResultSet,查詢所返回的結(jié)果保存在此對(duì)象中,用它可以瀏覽和存取數(shù)據(jù)庫內(nèi)的記錄。
1,通過jdbc-odbc橋使用odbc數(shù)據(jù)庫(并不需要jdbc?Drivers)
先在odbc?DSN(Data?Source?Name)設(shè)置處設(shè)置pubs?sysDSN,sa為username,密碼為空
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");//加載驅(qū)動(dòng)程序
con=DriverManager.getConnection("jdbc:odbc:pubs","sa","");//jdbc:odbc:pubs
con.close();
//應(yīng)當(dāng)catch?ClassNotFoundException和SQLException
Connection的getWarning方法返回一個(gè)SQLWarning對(duì)象,在連接之前應(yīng)當(dāng)先檢查。
使用jdbc-odbc的最大好處是:免費(fèi)的。但是性能受odbc的限制,而且一般odbc驅(qū)動(dòng)比較昂貴。
2,使用專門的jdbc驅(qū)動(dòng)程序。//此處是mm?jdbc?Driver
先將jar文件放在ClassPath里面。
Class.forName("org.gjt.mm.mysql.Driver");
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname","root","");
con.close();
可見使用何種方式連接何種數(shù)據(jù)庫與數(shù)據(jù)庫的操作和連接數(shù)據(jù)庫是無關(guān)的。
三,查詢數(shù)據(jù)庫
Statement?stmt=con.createStatement();
stmt.setMaxRows()可以控制輸出記錄最大數(shù)量;
ResultSet?rs=stmt.executeQuery("select?.....");
ResultSet指向當(dāng)前記錄:
int?userId=rs.getInt("userid");
String?userName=rs.getString("username");
...或者用序號(hào)(從1開始的)
int?userId=rs.getInt(1);
Stirng?userName=rs.getString(2);
ClassNotFoundException是由于Class.forName()無法載入jdbc驅(qū)動(dòng)程序觸發(fā)的
SQLException是jdbc在執(zhí)行過程中發(fā)生問題時(shí)產(chǎn)生。有一個(gè)額外的方法getNextException()
catch(SQLException?e){
out.println(e.getMessage());
while(e=e.getNextException()){
out.println(e.getMessage());
}
}
一般來說并不建議在jsp中編寫數(shù)據(jù)庫的訪問程序,可以將數(shù)據(jù)庫的訪問封裝在一個(gè)javabean中。
四,ResultSet深入
1,ResultSetMetaData
ResultSet?rs=stmt.executeQuery("select....");
ResultSetMetaData?rsmd=rs.getMetaData();?//獲取ResultSetMateData對(duì)象
int?numberOfColumns=rsmd.getColumnCount();//返回列數(shù)
boolean?b=rsmd.isSearchable(int?i);//返回第i列是否可以用于where子句
String?c=rsmd.getColumnLabel(int?i);//獲取第i列的列標(biāo)
Objcet?obj=rs.getObject();
if(obj!=null)out.println(obj.toString());
else?println("");
2,SQL類型與ResultSet的getObject返回類型及對(duì)應(yīng)的XXX?getXXX()方法
SQL類型?JSP類型?對(duì)應(yīng)的getXXX()方法
————————————————————————————————————————————
CHAR?String?String?getString()
VARCHAR?String?String?getString()
LONGVARCHAR?String?InputStream?getAsciiStream()/getUnicodeStream()
NUMERIC?java.math.BigDecimal?java.math.BigDecimal?getBigDecimal()
DECIMAL?同上
BIT?Boolean?boolean?getBoolean()
TINYINT?Integer?byte?getByte()
SMALLINT?Integer?short?getShort()
INTEGER?Integer?int?getInt()
BIGINT?Long?long?getLong()
REAL?Float?float?getFloat()
FLOAT?Double?double?getDouble()
DOUBLE?Double?double?getDouble()
BINARY?byte[]?byte[]?getBytes()
VARBINARY?byte[]?byte[]?getBytes()
LONGVARBINARY?byte[]?InputStream?getBinaryStream()
DATE?java.sql.Date?java.sql.Date?getDate()
TIME?java.sql.Time?java.sql.Time?getTime()
TIMESTAMP?java.sql.Timestamp?java.sql.Timestamp?getTimestamp()
3,null
int?i=rs.getInt("age");
if(!rs.wasNull())....//RecordSet::wasNull()用來檢查null
4,存取大字符串和二進(jìn)制文本
對(duì)于數(shù)據(jù)庫中l(wèi)ongvarchar和langvarbinary進(jìn)行流操作
ResultSet?rs=stmt.executeQueryString("select?...");
BufferedReader?br=new?BufferedReader(new?InputStream(rs.getAsciiStream("vol1")));//長(zhǎng)文本串
BufferedReader?br=new?BufferedReader(new?InputStream(rs.getUnicodeStream("vol1")));
BufferedReader?br=new?BufferedReader(new?InputStream(rs.getBinaryStream("vol2")));//長(zhǎng)二進(jìn)制文本
//取數(shù)據(jù)必須在rs.getAsciiStream(),?rs.getUnicodeStream(),?rs.getBinaryStream()等之后馬上進(jìn)行
五,瀏覽ResultSet
1,JDBC2.0提供了更多瀏覽ResultSet的方法
首先,確定你的jdbc驅(qū)動(dòng)程序支持jdbc2.0
其次,由Connection生成Statement時(shí)要指定參數(shù)
Statement?stmt=con.getStatement("游標(biāo)類型",?"記錄更新權(quán)限");
游標(biāo)類型:
ResultSet.TYPE_FORWORD_ONLY:只可以向前移動(dòng)
ResultSet.TYPE_SCROLL_INSENSITIVE:可卷動(dòng)。但是不受其他用戶對(duì)數(shù)據(jù)庫更改的影響。
ResultSet.TYPE_SCROLL_SENSITIVE:可卷動(dòng)。當(dāng)其他用戶更改數(shù)據(jù)庫時(shí)這個(gè)記錄也會(huì)改變。
記錄更新權(quán)限:
ResultSet.CONCUR_READ_ONLY,只讀
ResultSet.CONCUR_UPDATABLE,可更新
getStatement()缺省參數(shù):getStatement(ResultSet.TYPE_FORWORD_ONLY,?ResultSet.CONCUR_READ_ONLY)
2,如果ResultSet是可卷動(dòng)的,以下函數(shù)可以使用:
rs.absolute()//絕對(duì)位置,負(fù)數(shù)表示從后面數(shù)
rs.first()第一條
rs.last()最后一條
rs.previoust()前一條
rs.next()后一條
rs.beforeFirst()第一條之前
rs.afterLast()最后之后
rs.isFirst(),rs.isLast(),rs.isBeforeFirst(),rs.isAfterLast
注意,剛打開的時(shí)候是處于第一條記錄之前的
六,更新數(shù)據(jù)庫
1,stmt.executeUpdate("strSql"),strSql是一條sql更新語句。update,insert,delete返回影響到的條數(shù)
2,stmt.execute()方法在不知道sql語句是查詢還是更新的時(shí)候用。如果產(chǎn)生一條以上的對(duì)象時(shí),返回true,此時(shí)可用?stmt.getResultSet()和stmt.getUpdateCount()來獲取execute結(jié)果,如果不返回ResultSet對(duì)象則返回false.
3,除了Statement的executeUpdate之外還可以用ResultSet:
rs.updateInt(1,10);
rs.updateString(2,"sfafd");
rs.updateRow();
七,使用預(yù)編譯PreparedStatement
PreparedStatement對(duì)象和Statement對(duì)象類似,都可以用來執(zhí)行SQL語句。不同在于,數(shù)據(jù)庫會(huì)對(duì)PreparedStatement的SQL語句進(jìn)行預(yù)編譯,而且仍舊能輸入?yún)?shù)并重復(fù)執(zhí)行編譯好的查詢速度比未編譯的要快。
PreparedStatement?stmt=con.preparedStatement("Insert?Into?users(userid,?username)?values(?,?)");
stmt.clearParameters();
stmt.setInt(1,2);
stmt.setString(2,"Big");
stmt.executeUpdate();
八,執(zhí)行存儲(chǔ)過程
1,JDBC調(diào)用存儲(chǔ)過程,并使用存儲(chǔ)過程的返回值。這樣可以將處理工作分為服務(wù)端和客戶端兩部分,并大大加快系統(tǒng)的設(shè)計(jì)和開發(fā)的時(shí)間。比如可以重復(fù)使用服務(wù)器上的組件。使用存儲(chǔ)過程之后大量諸計(jì)算工作可以交給數(shù)據(jù)庫服務(wù)器來處理,這將降低Web服務(wù)器的負(fù)載,從而提高整個(gè)系統(tǒng)的性能。
2,有兩個(gè)表UserMain{UserID,UserName,UserType},UserRef{BrefID,?UserID,?UserBrief}
下面的存儲(chǔ)過程可以接受jdbc傳來的參數(shù),新增內(nèi)容到UserMain和UserRef,并輸出一個(gè)OutUserID.
CREATE?PROCEDURE?ap_adduser
(
@OutUserID?int?output,?//此為輸出參數(shù),output標(biāo)記
@UserName?varchar(25),?//參數(shù)表示方法:"@XXX"為變量名,"變量名?類型?[output]"
@UserType?tinyint,
@UserBrief?varchar(255),
)
AS
Declare?@UserID?int?//定義局部變量
insert?into?UserMain(UserName,?UserType)
values(@UserName,@UserType)
select?@UserID=@@IDENTITY?//賦值用select,此處自動(dòng)獲得ID
insert?into?UserRef(UserID,?UserBrief)
select?@OutUserID=@UserID
GO/*結(jié)束,基本結(jié)構(gòu):
CREATE?PROCEDURE?procedureName(
parameters
)
AS
actions
GO
*/
JSP頁面中這樣使用:
CallableStatement?stmt=con.prepareCall("{call?ap_adduser(?,?,?,?)}");
stmt.registerOutParameter(1,Types.INTEGER,1);//注冊(cè)輸出變量
stmt.setString(2,"edmund");
stmt.setInt(3,1);
stmt.setString(4,"description");
stmt.execute();
int?userid=stmt.getInt(1);
stmt.close()
八,使用事務(wù)
1,事務(wù)中的操作是一個(gè)整體,要么都執(zhí)行成功要么都不成功:事務(wù)開始后,如果所有的改變都正確,則使用commit方法將這些動(dòng)作全部存入數(shù)據(jù)庫,否則就使用rollback取消所有的改變動(dòng)作,而這時(shí)數(shù)據(jù)庫中的數(shù)據(jù)和執(zhí)行事務(wù)前的是相同的。
2,使用事務(wù)時(shí)應(yīng)當(dāng)先用?con.setAutoCommit(false),最后使用commit或者rollback
3,rollback一般在catch段執(zhí)行
九,數(shù)據(jù)庫連接池
1,如果有一個(gè)數(shù)據(jù)庫連接請(qǐng)求并且連接中沒有連接,則生成一個(gè)新的連接。這個(gè)連接使用完之后并不關(guān)閉它,而是將它放入連接池。在這個(gè)過程中,還要判斷連接池中的連接是否超期。如果超期則將它關(guān)閉。
2,有很多已有的Connection?Pool包可以使用。
3,一般將Connection?Pool作為一個(gè)application作用域的變量使用
<jsp:useBean?id="pool"?scope="application"?class="javastart.tools.ConnectionPool"?/>
<%@page?import="java.sql.*"%>
<%@page?import="javastart.tools.*"%>
<!--javastart.tools是你的Connection?Pool所在的地方-->
DBConnection?con=null;
try{
con=pool.getConnection("sun.jdbc.odbc.JdbcOdbcDriver","jdbc:odbc:access","","");
Statement?stmt=con.createStatement();
stmt.setMaxRows(10);
String?query=request.getParameter("quey");
ResultSet?rs=stml.executeQuery(query);
ResultSetMetaData?rsmd=rs.getMetaData();
}
.....
finally{
pool.releaseConnection(con);
}
也可以使用一個(gè)Servlet初始化連接池