| 特性 | BLOB (Binary Large Object) | CLOB (Character Large Object) |
|---|---|---|
| 存儲內容 | 二進制字節流 (圖片、PDF、視頻、加密數據) | 字符文本 (大文本、日誌、XML、JSON、代碼) |
| 字符集轉換 | 無,原樣存取 | 有,按連接字符集編解碼 |
| Hibernate 映射 | @Lob @Basic(fetch=LAZY) byte[] / Blob |
@Lob @Basic(fetch=LAZY) String / Clob |
| Spring 類型 | BlobByteArrayType / BlobType |
ClobStringType / ClobType |
現象:用 ClobStringType 存儲文本文件,上傳正常,但下載後**換行符消失、特殊字符變亂碼**。
原因:ClobStringType 將文件讀為 String,經過字符集編解碼 (如 UTF-8),若文件編碼不一致或含二進制字符,會被替換/截斷。**CLOB 適合「純文本內容」,不適合「文件原樣存取」**。
IF 文件需原樣下載 (圖片、PDF、Word、壓縮包、加密文件、任意二進制):
USE BLOB + byte[] / Blob
ELIF 純文本內容需全文搜索、字符級處理 (日誌、文章、代碼、配置):
USE CLOB + String / Clob
ELSE:
USE BLOB -- 兜底最安全
@Entity
@Table(name = "document")
public class Document {
@Id @GeneratedValue
private Long id;
@Lob
@Basic(fetch = FetchType.LAZY) -- 關鍵:大對象延遲加載,避免查詢列表時全載入
@Column(name = "content", columnDefinition = "LONGBLOB")
private byte[] content; // BLOB 用 byte[]
// CLOB 版本
// @Lob
// @Basic(fetch = FetchType.LAZY)
// @Column(name = "content", columnDefinition = "LONGTEXT")
// private String content; // CLOB 用 String
// getters/setters
}
@Repository
public interface DocumentRepository extends JpaRepository {
// 查詢列表時不加載 content (得益於 LAZY)
List findByCategory(String category);
// 單獨加載 content
@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "org.hibernate.fetchProfile", value = "WITH_CONTENT")})
Optional findWithContentById(Long id);
}
document_meta (id, name, size, path) + document_content (id, chunk_index, data BLOB) 分塊存儲,單塊 ≤ 4MB。log_slave_updates)。InputStream/OutputStream 避免 JVM OOM,Hibernate Blob.getBinaryStream() 支援流式。binlog_format=ROW、max_allowed_packet=1G、定期清理 Binlog。mysqldump 極慢,改用物理備份 xtrabackup 或快照備份。ClobStringType 存二進制文件 → 下載損壞。@Lob 不加 @Basic(fetch=LAZY) → 列表查詢全量加載大字段,OOM。columnDefinition="BLOB" 未指定 LONGBLOB → 默認 64KB 截斷。Files.probeContentType(path) 或魔數檢測,決定 BLOB/CLOB。MessageDigest.isEqual(originalBytes, downloadedBytes) 校驗 MD5/SHA256 一致。總結:**BLOB 存文件,CLOB 存文本**。Spring/Hibernate 配置關鍵在 @Basic(fetch=LAZY) + 正確類型映射。生產環境**大文件上對象存儲**,DB 只存元數據,才是架構正解。