| 類型 | 最大長度 | 特性 |
|---|---|---|
| TINYBLOB / TINYTEXT | 255 位元組/字元 | 極小二進位/文本 |
| BLOB / TEXT | 65,535 (64KB) | 標準大小 |
| MEDIUMBLOB / MEDIUMTEXT | 16,777,215 (16MB) | 中等大物件 |
| LONGBLOB / LONGTEXT | 4,294,967,295 (4GB) | 超大物件,受限於 max_allowed_packet 與記憶體 |
關鍵差異:BLOB 視為二進位字串(無字符集、按位元組比較);TEXT 視為字符字串(有字符集、按排序規則比較)。
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`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
public static void insertBlob() {
Connection conn = DBToolkit.getConnection();
String sql = "INSERT INTO user (name, pswd, pic) VALUES (?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql);
InputStream in = new BufferedInputStream(new FileInputStream("D:/PIC.PNG"))) {
ps.setString(1, "zhangsan");
ps.setString(2, "111");
ps.setBinaryStream(3, in, (int) new File("D:/PIC.PNG").length());
ps.executeUpdate();
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
public static void queryBlob() {
String sql = "SELECT pic FROM user WHERE id = 24";
try (Connection conn = DBToolkit.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
try (InputStream in = rs.getBinaryStream(1);
OutputStream out = new BufferedOutputStream(new FileOutputStream("D:/PIC_COPY.PNG"))) {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
}
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
注意:setBinaryStream第三參數長度必須準確,否則可能寫入不完整。大檔案建議分塊寫入或使用setBlob。
public static void insertClob() {
String sql = "INSERT INTO user (name, pswd, remark) VALUES (?, ?, ?)";
try (Connection conn = DBToolkit.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
Reader reader = new InputStreamReader(new FileInputStream("D:/TEXT.txt"), "UTF-8")) {
ps.setString(1, "zhangsan");
ps.setString(2, "111");
ps.setCharacterStream(3, reader, (int) new File("D:/TEXT.txt").length());
ps.executeUpdate();
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
public static void queryClob() {
String sql = "SELECT remark FROM user WHERE id = 1";
try (Connection conn = DBToolkit.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
try (Reader reader = rs.getCharacterStream(1);
Writer writer = new OutputStreamWriter(new FileOutputStream("D:/TEXT_COPY.txt"), "UTF-8")) {
char[] buf = new char[1024];
int len;
while ((len = reader.read(buf)) > 0) {
writer.write(buf, 0, len);
}
}
}
} catch (IOException | SQLException e) {
e.printStackTrace();
}
}
現象:直接使用 getCharacterStream() 讀取的 CLOB,中文可能亂碼。
原因:JDBC 驅動在內部已按連接字符集(characterEncoding 參數)將二進位數據解碼為 char 陣列。若資料庫存儲編碼、連接編碼、JVM 默認編碼三者不一致,會發生雙重編碼/解碼錯誤。
解決方案:
CHARSET=utf8mb4,JDBC URL 附加 ?characterEncoding=UTF-8&useUnicode=true,JVM -Dfile.encoding=UTF-8。setClob/getClob + 顯式編碼(JDBC 4.0+):// 寫入
Clob clob = conn.createClob();
clob.setString(1, new String(Files.readAllBytes(path), "UTF-8"));
ps.setClob(3, clob);
// 讀取
Clob clob = rs.getClob(1);
String content = clob.getSubString(1, (int) clob.length());
max_allowed_packet 足夠大(如 64M)。BufferedInputStream/OutputStream)。SELECT * 拉取大字段,按需查詢。