在 Java 電商項目中,商品圖片的存儲方式直接影響系統性能、擴展性及維護成本。主要有三種主流方案:
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 數據庫存儲 (BLOB) | 事務一致性強,備份還原簡單,數據完整性高 | 數據庫體積膨脹快,讀寫性能差,佔用昂貴的數據庫連接資源,難以做 CDN 加速 | 圖片極小、數量少、對一致性要求極高的場景 (如證件照、簽名) |
| 服務器本地文件系統 | 實現簡單,讀取速度快,不佔用數據庫資源 | 單點故障風險,擴展困難 (集群需共享存儲/同步),備份麻煩,難以應對高並發 | 單機部署、中小型項目、內部管理系統 |
| 分布式文件系統 / 對象存儲 (推薦) | 高可用、無限擴展、支持 CDN 加速、成本低、運維成熟 (MinIO, FastDFS, 阿里云 OSS, AWS S3) | 引入外部依賴,架構稍複雜,需處理上傳簽名、防盜鏈等邏輯 | 生產環境電商、高並發應用、雲原生架構 |
將圖片文件上傳至對象存儲,數據庫僅存儲 Object Key (路徑) 和元數據 (大小、格式、寬高)。
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>
@Service
public class FileStorageService {
private final MinioClient minioClient;
private final String bucketName = "shop-images";
public String upload(MultipartFile file) throws Exception {
String objectName = UUID.randomUUID() + "_" + file.getOriginalFilename();
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
return objectName; // 返回存儲鍵,存入數據庫
}
public String getPresignedUrl(String objectName) {
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.bucket(bucketName).object(objectName).method(Method.GET).expiry(3600).build());
}
}
CREATE TABLE product_image (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
product_id BIGINT NOT NULL,
object_key VARCHAR(500) NOT NULL COMMENT 'OSS 存儲鍵',
url VARCHAR(1000) COMMENT 'CDN 加速域名拼接後的完整 URL',
sort INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
對於現代 Java 電商系統,**對象存儲 (OSS/MinIO) + 數據庫存元數據** 是性價比最高、擴展性最強的方案。早期原型可用本地文件系統,但上線前務必遷移至分布式存儲。