JDBC 存取 MySQL BLOB/MEDIUMBLOB/LONGBLOB,核心用 PreparedStatement.setBinaryStream() 流式傳輸,避免全量入內存;讀取用 ResultSet.getBlob() + getBytes()。
| 類型 | 最大長度 | 適用場景 |
|---|---|---|
| TINYBLOB | 255 B | 極小圖標 |
| BLOB | 64 KB | 縮略圖 |
| MEDIUMBLOB | 16 MB | 普通圖片/文檔 |
| LONGBLOB | 4 GB | 大文件/視頻 |
public void saveBinary(String filePath, Connection conn) throws Exception {
File file = new File(filePath);
try (InputStream is = new FileInputStream(file);
PreparedStatement ps = conn.prepareStatement(
"INSERT INTO bank_voice(name, data) VALUES (?, ?)")) {
ps.setString(1, file.getName());
ps.setBinaryStream(2, is, (int) file.length()); // 流式,無需 byte[]
ps.executeUpdate();
}
}
public void getBinary(String name, String destPath, Connection conn) throws Exception {
try (PreparedStatement ps = conn.prepareStatement("SELECT data FROM bank_voice WHERE name=?");
FileOutputStream fos = new FileOutputStream(destPath)) {
ps.setString(1, name);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
Blob blob = rs.getBlob("data");
fos.write(blob.getBytes(1, (int) blob.length()));
}
}
}
}
# my.ini / my.cnf
[mysqld]
max_allowed_packet = 16M # 或 64M/256M,≥ 最大文件
修改後 net stop mysql && net start mysql(Windows)或 systemctl restart mysqld(Linux)。
連接字符串同步:jdbc:mysql://localhost:3306/db?maxAllowedPacket=16777216。
| 異常 | 原因 | 解決 |
|---|---|---|
PacketTooBigException | 文件 > max_allowed_packet | 調大配置並重啟 |
OutOfMemoryError | 用 byte[] 全量讀取大文件 | 改用 setBinaryStream 流式 |
Communications link failure | 傳輸超時 | 調大 net_write_timeout/net_read_timeout |
public static File downLoadFile(String urlStr) throws Exception {
URL url = new URL(urlStr);
try (InputStream is = url.openStream();
FileOutputStream fos = new FileOutputStream("D:/temp.bin")) {
byte[] buf = new byte[8192];
int len;
while ((len = is.read(buf)) != -1) fos.write(buf, 0, len);
return new File("D:/temp.bin");
}
}
innodb_file_per_table、定期 OPTIMIZE TABLE 整理碎片。maxLifetime 設短(30min),防止長連接持有大 Blob 導致內存壓力。