????
posted on 2005-05-27 09:36 輕松逍遙子 最近在J2EE的項目中需要使用LOB字段保存文本信息以及圖片和文件,到網上搜拉一下,還不少,仔細看拉一下,但都不是很全有的還有錯誤,經過幾天的實踐,把問題都解決拉,順便總結一下,希望對需要的朋友有點參考
LOB中我們用的比較多的主要有兩種CLOB和BLOB,我們對兩種類型分別討論
1.CLOB是字符型LOB,主要存儲文本信息,,最長為4G.,在J2EE程序中,比如網頁的textarea中的字符信息比較長,Varchar2字段類型不能滿足時,我們就得用CLOB數據類型,我們這次項目中就碰到這種情況.現在我們先說說如何存取CLOB字段
現在我要把網頁中的textarea元素的信息保存到數據庫的CLOB字段中, 我們都知道textarea中的信息當然不能直接保存成CLOB,我們在后臺得到的是String類型的,不多說拉,我們還是以一個實例講吧!
先建一個test表,表有2個字段:ID,CONTENTS,其中CONTENTS保存CLOB類型的文本數據
create table TEST ( ID VARCHAR2(18) not null, CONTENTS CLOB, )
接著我們編寫一個測試用的jsp文件ClobTest.jsp,代碼如下
<%@ page language="java" contentType="text/html; charset=gb2312" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Clob對象的存取測試</title>
</head>
<body>
<form name="test" method="post" action="clobTest.action">
<table width="80%" height="88" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="30" align="center">輸入ID號<input type="text" name="ID">
</tr>
<tr>
<td align="center">
<textarea rows="28" cols="68" name="CONTENTS">
注冊用戶需遵守:
尊重會員個人隱私、保障會員隱私安全是CSDN的一項基本政策,CSDN不會公開、編輯或透露會員的注冊資料,除非符合以下情況: (1) 根據中華人民共和國國家安全機構、公安部門的要求及根據相應的法律程序要求。 (2) 維護CSDN的商標所有權及其它權益。 (3) 在緊急情況下竭力維護會員個人、其它社會個體和社會大眾的安全。 (4) 嚴重違反CSDN有關規定。 CSDN保留結束會員使用網絡服務資格的權利,并保證結束會員資格后仍為會員保密所有個人隱私。
</textarea>
</td>
</tr>
<tr>
<td align="center">
<input type="submit" name="Submit" value="提交">
</td>
</tr>
</table>
</form>
</body>
</html>
點擊”提交”按鈕,我們在后臺的到的是2個String類型的對象
String strID = request.getParameter(“ID”);
String strCONTENTS = request.getParameter(“CONTENTS”);
接著我們要做的任務就是如何把String類型CONTENTS存到數據庫中的CLOB類型字段中!
注意:LOB數據不能象其它類型數據一樣直接插入(INSERT)。插入前必須先插入一個空的LOB對象,CLOB類型的空對象為EMPTY_CLOB(),BLOB類型的空對象為EMPTY_BLOB()。之后通過SELECT命令查詢得到先前插入的記錄并鎖定,繼而將空對象修改為所要插入的LOB對象。
//我們先插入一個空的CLOB對象
public int insertEmptyClob() throws Exception {
Statement statement = null;
int intResult = -1;
try {
//創建數據庫操作語句
statement = connection.createStatement();
//定義SQL語句
String strSQL = “INSET INTO TEST (ID,CONTENTS) VALUES(strID, EMPTY_CLOB())”;
//執行SQL語句
intResult = statement.executeUpdate(strSQL);
System.out.println(" intResult valus is"+intResult);
return intResult;
} catch(Exception e) {
e.printStackTrace();
return -1;
} finally {
if (statement != null) {
statement.close();
}
}
}
//把strCONTENT插入CLOB字段
public void insertClob() throws Exception {
Statement statement = null;
ResultSet resultset = null;
try {
//設置不自動提交
connection.setAutoCommit(false);
//創建數據庫操作語句
statement = connection.createStatement();
//定義SQL語句
String strSQL = “SELECT CONTENTS FROM TEST WHERE ID=strID"”
resultset = statement.executeQuery(strSQL);
oracle.sql.CLOB contents = null;
while(resultset.next()) {
//取出CLOB對象
contents = (oracle.sql.CLOB)resultset.getClob("CONTENTS");
}
Writer out = contents.getCharacterOutputStream();
out.write(strContents);
out.flush();
out.close();
//數據庫提交
connection.commit();
} catch(Exception e) {
e.printStackTrace();
}finally{
if(resultset != null) {
resultset.close();
}
if(statement != null) {
statement.close();
}
}
}
OK,我們已經把這段文本以CLOB字段的形式保存到數據庫中了,在實際應用中,如果要保存或修改一條記錄,我們要分2步做,先保存或修改非LOB字段類型的字段,再保存或修改LOB字段!接下來我們來把剛才保存到數據庫中的CLOB字段讀到jsp頁面中去。
我們在保存的時候,CLOB字段會把上面textarea中的文本按原來的格式一行一行(包括空格)都保存到CLOB字段中,讀取的時候我們只要按照原來格式讀起出來就行了(我這里自己用了一個小處理方法,但如果你有更好的方法請告訴我)。在這里我們把CLOB讀到StringBuffer中,為了保存不同行我在行之間加了個“&”字符來區分。最后轉化成String
放到VO中,這樣就保證從前臺到后臺,從后臺到前臺的數據傳遞的一致性!代碼如下:
/**
* 獲取CLOB文本對象
* @param sbSQL
* @return
* @throws java.lang.Exception
*/
public String selectIncludeClob(StringBuffer sbSQL) throws Exception {
Statement stmt = null;
ResultSet rs = null;
StringBuffer sbResult = new StringBuffer();
try {
//設定數據庫不自動提交
//connection.setAutoCommit(false);
//創建數據庫操作語句
stmt = connection.createStatement();
//獲取結果集
rs = stmt.executeQuery(sbSQL.toString());
while(rs.next()) {
CLOB clob = (CLOB)rs.getClob("CONTENTS");
Reader isClob = clob.getCharacterStream();
BufferedReader bfClob = new BufferedReader(isClob);
String strClob = bfClob.readLine();
while(strClob != null) {
sbResult.append(strClob);
sbResult.append("&");
strClob = bfClob.readLine();
}
}
//提交事務
// connection.commit();
} catch(Exception e) {
e.printStackTrace();
throw e;
} finally {
if(rs != null) {
rs.close();
}
if(stmt != null) {
stmt.close();
}
}
return sbResult.toString();
}
到jsp頁面中,我們從VO中獲取改文本信息。
<textarea rows="42" cols="68" name="CONTENTS" style="border-style: solid; border-color: #FFFFFF; font-family:仿宋_GB2312; font-size:14pt; line-height:200%; margin-top:8; margin-bottom:6" >
<%
String content = vo.getContent();
String[] contentArray = content.split("&");
for(int i=0;i<contentArray.length;i++) {
String s= contentArray[i];
out.println(s);
}
%>
</textarea>
這樣我們就保證什么格式保存就以什么格式顯示。
2.BLOB字段,二進制LOB,主要存儲二進制數據,最長為4G,在J2EE程序中,一般類似于圖片和文件的保存。當然也有另一種方法,就把圖片和文件保存在硬盤上,數據庫中只保存圖片的鏈接地址和文件在服務器上的路徑。如果遇到文件和圖片比較重要的還是需要保存到數據庫中(例如:我們做國土資源項目的時候,好多圖片、文件就很重要,需要保存到數據庫中),下面我寫一個保存文件到數據庫的Blob字段和從數據庫的Blob字段中獲取文件的方法(當然完全應用還要做其他工作,這里就不多說了,如果你不清楚的可以問我):
/**
* 把上傳的文件保存到數據庫的Blob字段中
* @param strTableName 對應的表名稱
* @param strColumnName 表中保存文件的Blob字段名稱
* @param inputStream 輸入的文件流
* @param sbSQLWhere where條件
* @throws java.lang.Exception
*/
public static void fileUpload(String strTableName,
String strColumnName,
InputStream inputStream,
StringBuffer sbSQLWhere)
throws Exception {
Connection con = null;
ResultSet resultset = null;
Statement stmt = null;
try {
//得到數據庫連接
con = DBConnector.getConnection();
//構建查詢語句
StringBuffer sbSQL = new StringBuffer();
sbSQL.append(" UPDATE ");
sbSQL.append(strTableName);
sbSQL.append(" SET ");
sbSQL.append(strColumnName);
sbSQL.append("=EMPTY_BLOB() ");
sbSQL.append(sbSQLWhere);
System.out.println(" update sql value is*******"+sbSQL.toString());
//獲取數據庫操作語句
stmt=con.createStatement();
//插入空的blob對象
stmt.executeUpdate(sbSQL.toString());
con.setAutoCommit(false);
StringBuffer sbSQLBlob = new StringBuffer();
sbSQLBlob.append(" SELECT ");
sbSQLBlob.append(strColumnName);
sbSQLBlob.append(" FROM ");
sbSQLBlob.append(strTableName);
sbSQLBlob.append(sbSQLWhere);
sbSQLBlob.append(" FOR UPDATE");
System.out.println(" select sql value is*********"+sbSQL.toString());
resultset =stmt.executeQuery(sbSQLBlob.toString());
while (resultset.next()) {
/* 取出此BLOB對象 */
oracle.sql.BLOB blob = (oracle.sql.BLOB)resultset.getBlob("BODY");
/* 向BLOB對象中寫入數據 */
BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
BufferedInputStream in = new BufferedInputStream(inputStream);
int c;
while ((c=in.read())!=-1) {
out.write(c);
}
in.close();
out.close();
}
con.setAutoCommit(false);
con.commit();
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
if (stmt != null) {
stmt.close();
}
if (resultset != null) {
resultset.close();
}
if (con!=null) {
con.close();
}
}
}
下面的方法是從數據庫中得到上傳的文件的輸入流,把輸入流寫到servlet流中,再從頁面中獲取,servlet就不寫了。
/**
* 方法描述:得到數據庫上傳的文件數據
*
* 輸入參數: 1:表名(String)
* 2:字段名(String)
* 3: Where條件(StringBuffer)
* 5: 輸出流(ServletOutputStream)
*
* 輸出參數:void
* 編寫人: */
public static void getdownFile(String strTableName,
String strColumnName,
StringBuffer sbSQLWhere,
ServletOutputStream sos) throws Exception {
Connection con = null;
PreparedStatement ps = null;
ResultSet resultset = null;
try {
//得到數據庫連接
con = DBConnector.getConnection();
StringBuffer sbSQL = new StringBuffer();
//構建查詢語句
sbSQL.append(" SELECT " + strColumnName + " FROM " + strTableName);
sbSQL.append(sbSQLWhere);
System.out.println(" sql value is:"+sbSQLWhere.toString());
ps = con.prepareStatement(sbSQL.toString());
//執行查詢
resultset = ps.executeQuery();
while (resultset.next()) {
//讀取數據流
InputStream is = resultset.getBinaryStream(strColumnName);
byte[] buf = new byte[2048];
while(is.read(buf)!=-1) {
//把數據流按塊寫到servlet的輸出流中
sos.write(buf);
}
}
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
} finally {
if (ps != null) {
ps.close();
}
if (resultset != null) {
resultset.close();
}
if (con!=null) {
con.close();
}
}
}
圖片的保存和文件的保存一樣,如果不清楚的可以和我聯系
后記:
平時總忙著做項目,閑的時候也很懶,總想把自己實際中的一些問題和解決方法小結一下,但總沒完成,這是第一次寫,寫的不好或不清楚的地方請包涵,下次改進,也希望大家多提意見,大家一起進步!?。。。。。。。。?! |