不管你是新手還是老手,大字段數據的操作常常令你感到很頭痛。因為大字段有些特 殊,不同數據庫處理的方式不一樣,大字段的操作常常是以流的方式來處理的。而非一般 的字段,一次即可讀出數據。本人以前用到Spring+iBatis架構來操作大字段,結果以慘 烈失敗而告終,在網上尋求解決方案,也沒找到答案。最終以JDBC來實現了大字段操作部 分。
本文以MySQL為例,通過最基本的JDBC技術來處理大字段的插入、讀取操作。
環境:
MySQL5.1
JDK1.5
一、認識MySQL的大字段類型
BLOB是一個二進制大對象,可以容納可變數量的數據。有4種BLOB類型:TINYBLOB、 BLOB、MEDIUMBLOB和LONGBLOB。它們只是可容納值的最大長度不同。
有4種TEXT類型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。這些對應4種BLOB類型, 有相同的最大長度和存儲需求。
BLOB 列被視為二進制字符串(字節字符串)。TEXT列被視為非二進制字符串(字符字符 串)。BLOB列沒有字符集,並且排序和比較基於列值字節的數值值。TEXT列有一個字符集 ,並且根據字符集的 校對規則對值進行排序和比較。
在TEXT或BLOB列的存儲或檢索過程中,不存在大小寫轉換。
當未運行在嚴格模式時,如果你為BLOB或TEXT列分配一個超過該列類型的最大長度的 值值,值被截取以保證適合。
幾種類型的大字段最大長度說明:
TINYBLOB最大長度為255(2^[8]–1)字節的BLOB列。
TINYTEXT最大長度為255(2^[8]–1)字符的TEXT列。
BLOB[(M)]最大長度為65,535(2^[16]–1)字節的BLOB列。可以給出該類型的可選長度M 。如果給出,則MySQL將列創建為最小的但足以容納M字節長的值的BLOB類型。
TEXT[(M)]最大長度為65,535(2^[16]–1)字符的TEXT列。可以給出可選長度M。則 MySQL將列創建為最小的但足以容納M字符長的值的TEXT類型。
MEDIUMBLOB最大長度為16,777,215(2^[24]–1)字節的BLOB列。
MEDIUMTEXT最大長度為16,777,215(2^[24]–1)字符的TEXT列。
LONGBLOB最大長度為4,294,967,295或4GB(2^[32]–1)字節的BLOB列。LONGBLOB列的最 大有效(允許的)長度取決於客戶端/服務器協議中配置最大包大小和可用的內存。
LONGTEXT最大長度為4,294,967,295或4GB(2^[32]–1)字符的TEXT列。LONGTEXT列的最 大有效(允許的)長度取決於客戶端/服務器協議中配置最大包大小和可用的內存。
二、創建測試環境
create table user (
id int(11) not null auto_increment,
name varchar(50) not null,
pswd varchar(50) default null,
pic longblob,
remark longtext,
primary key (id)
);
三、插入讀取blob
import lavasoft.common.DBToolkit;
import java.io.*;
import java.sql.*;
/**
* 操作MySQL5的blob字段
*
* @author leizhimin 2009-12-3 11:34:50
*/
public class BlobTest {
public static void main(String[] args) {
insertBlob();
queryBlob();
}
public static void insertBlob() {
Connection conn = DBToolkit.getConnection();
PreparedStatement ps = null;
try {
String sql = "insert into testdb.user (name, pswd, pic) values (?, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "zhangsan");
ps.setString(2, "111");
//設置二進制參數
File file = new File ("D:\\new\\dbtools\\src\\res\\PIC.PNG");
InputStream in = new BufferedInputStream(new FileInputStream(file));
ps.setBinaryStream(3, in, (int) file.length());
ps.executeUpdate();
in.close();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBToolkit.closeConnection (conn);
}
}
public static void queryBlob() {
Connection conn = DBToolkit.getConnection();
PreparedStatement ps = null;
Statement stmt = null;
ResultSet rs = null;
try {
String sql = "select pic from user where id = 24";
stmt = conn.createStatement();
rs = stmt.executeQuery (sql);
if (rs.next()) {
InputStream in = rs.getBinaryStream(1);
File file = new File("D:\\new\\dbtools\\src\\res\\PIC_COPY.PNG");
OutputStream out = new BufferedOutputStream(new FileOutputStream (file));
byte[] buff = new byte[1024];
for (int i = 0; (i = in.read(buff)) > 0;) {
out.write(buff, 0, i);
}
out.flush ();
out.close ();
in.close ();
}
rs.close();
stmt.close();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBToolkit.closeConnection (conn);
}
}
}
注意,要確保二進制數據長度足夠大,否則可能導致數據寫入不完整的問題。
三、插入讀取clob字段
clob在MySQL5中對應的就是text字段,可以根據實際需要選擇合適的長度。
package lavasoft.jdbctest;
import lavasoft.common.DBToolkit;
import java.io.*;
import java.sql.*;
/**
* 操作MySQL5的Clob字段
*
* @author leizhimin 2009-12-3 13:56:16
*/
public class ClobTest {
public static void main(String[] args) {
insertClob();
queryClob();
}
public static void insertClob() {
Connection conn = DBToolkit.getConnection();
PreparedStatement ps = null;
try {
String sql = "insert into testdb.user (name, pswd, remark) values (?, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "zhangsan");
ps.setString(2, "111");
//設置二進制參數
File file = new File ("D:\\new\\dbtools\\src\\res\\PIC.PNG");
// InputStreamReader reader = new InputStreamReader(new FileInputStream ("D:\\new\\dbtools\\src\\res\\TEXT.txt"),"GB18030");
InputStreamReader reader = new InputStreamReader(new FileInputStream ("D:\\new\\dbtools\\src\\res\\TEXT.txt"));
ps.setCharacterStream(3, reader, (int) file.length());
ps.executeUpdate();
reader.close();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBToolkit.closeConnection (conn);
}
}
public static void queryClob() {
Connection conn = DBToolkit.getConnection();
PreparedStatement ps = null;
Statement stmt = null;
ResultSet rs = null;
try {
String sql = "select remark from user where id = 1";
stmt = conn.createStatement();
rs = stmt.executeQuery (sql);
if (rs.next()) {
Reader reader = rs.getCharacterStream(1);
File file = new File("D:\\new\\dbtools\\src\\res\\TEXT_COPY.txt");
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream (file));
// OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream (file),"ISO-8859-1");
// OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream (file),"GB18030");
char[] buff = new char[1024];
for (int i = 0; (i = reader.read(buff)) > 0;) {
writer.write(buff, 0, i);
}
writer.flush();
writer.close();
reader.close();
}
rs.close();
stmt.close();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBToolkit.closeConnection (conn);
}
}
}
在處理blob字段時候,由於直接處理的是二進制流,所以沒啥問題。在處理clob字段 的時候,由於數據庫對clob是以字符的形式進行存儲,這就有一個編碼問題。本文雖然成 功的插入讀取了clob字段,但是還沒有解決亂碼問題,因為JDBC在獲取到clob的時候,已 經對其進行了編碼,Reader reader = rs.getCharacterStream(1); 這就導致了編碼的混 亂,如果要徹底解決,還需要看看MySQL驅動的實現。通過非常規手段來解決。為了繞開 此問題,可以將clob的數據存儲為blog來操作,可以避免此問題。
出處:http://lavasoft.blog.51cto.com/62575/238222