在使用 GORM 的 MySQL 驱动 (gorm.io/driver/mysql
) 时,如果需要实现文件上传功能(例如将文件内容存储到数据库的 BLOB/LONGBLOB 字段),以下是完整的实现步骤和注意事项:
1. 准备数据库表
确保表中包含二进制字段(如 BLOB
或 LONGBLOB
):
CREATE TABLE `files` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`data` LONGBLOB, -- 存储文件内容
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
对应 Go 结构体:
type File struct {
ID uint `gorm:"primaryKey"`
Name string
Data []byte // ← BLOB/LONGBLOB 字段
CreatedAt time.Time
}
2. 实现文件上传
(1) HTTP API 示例(Gin + GORM)
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
func UploadFile(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
// 1.获取上传的文件
file, err := c.FormFile("file") // <input type="file" name="file">
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
//2.读取文件内容到 []byte
uploadedFile, err := file.Open()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取文件"})
return
}
defer uploadedFile.Close()
fileData := make([]byte, file.Size)
_, err = uploadedFile.Read(fileData)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "文件读取失败"})
return
}
//3.保存到数据库
newFile := File{
Name: file.Filename,
Data: fileData,
}
result := db.Create(&newFile)
if result.Error != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "上传成功",
"file_id": newFile.ID,
"file_name": newFile.Name,
"size": len(newFile.Data),
})
}
(2) CURL测试上传
curl -X POST http://localhost:8080/upload \
-F "file=@/path/to/your/file.jpg" \
-H "Content-Type: multipart/form-data"
3.下载文件的实现
func DownloadFile(c *gin.Context) {
db := c.MustGet("db").(*gorm.DB)
id := c.Param("id")
var file File
if err := db.First(&file, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", file.Name))
c.Data(http.StatusOK,"application/octet-stream", file.Data)
}
访问方式:
GET /download/:id
4.关键注意事项
(1)性能优化
- 大文件处理:对于超大文件(如 >100MB),建议直接存储到对象存储(如 S3/MinIO),数据库中只存路径。
- 事务控制:大文件插入时启用事务避免内存溢出:
err = db.Transaction(func(tx *gorm.DB) error {
return tx.Create(&largeFile).Error
})
(2)MySQL配置
- 调整max_allowed_packet:确保 MySQL允许足够大的数据包:
SET GLOBAL max_allowed_packet=1073741824; --1GB
在 my.cnf中永久生效:
[mysqld]
max_allowed_packet=1G
(3)替代方案
如果频繁操作二进制数据,推荐以下组合:
场景 | 推荐方案 |
---|---|
小文件(<10MB) | 直接存BLOB |
大文件 | 对象存储+数据库存路径 |
如果有其他具体需求(如分片上传、进度监控等),可以进一步讨论!
内容由零声教学AI助手提供,问题来源于学员提问