@@ -23,11 +23,21 @@ func (e *FileUploadAndDownloadService) FindOrCreateFile(fileMd5 string, fileName
2323 cfile .FileMd5 = fileMd5
2424 cfile .FileName = fileName
2525 cfile .ChunkTotal = chunkTotal
26-
27- if errors .Is (global .GVA_DB .Where ("file_md5 = ? AND is_finish = ?" , fileMd5 , true ).First (& file ).Error , gorm .ErrRecordNotFound ) {
26+ // 检查是否存在已完成上传的文件(is_finish = true)
27+ // 同时使用 fileMd5 和 fileName 作为查询条件,确保文件唯一性
28+ // 原因:虽然 MD5 碰撞概率极低,但理论上仍可能发生(不同内容产生相同 MD5)
29+ // 同时使用 MD5 和文件名可以避免误匹配到错误的文件
30+ // 使用 errors.Is 判断是否为记录不存在的错误,这是 GORM 的标准做法
31+ // 好处:可以区分"记录不存在"和"其他数据库错误",逻辑更清晰
32+ if errors .Is (global .GVA_DB .Where ("file_md5 = ? AND file_name = ? AND is_finish = ?" , fileMd5 , fileName , true ).First (& file ).Error , gorm .ErrRecordNotFound ) {
33+ // 不存在已完成的文件,查找或创建未完成的文件记录
34+ // Preload("ExaFileChunk") 预加载关联的切片记录
35+ // 好处:一次查询获取文件信息和已上传切片列表,减少数据库查询次数
36+ // FirstOrCreate 如果找到则返回,找不到则创建,原子操作保证并发安全
2837 err = global .GVA_DB .Where ("file_md5 = ? AND file_name = ?" , fileMd5 , fileName ).Preload ("ExaFileChunk" ).FirstOrCreate (& file , cfile ).Error
2938 return file , err
3039 }
40+
3141 cfile .IsFinish = true
3242 cfile .FilePath = file .FilePath
3343 err = global .GVA_DB .Create (& cfile ).Error
@@ -39,7 +49,7 @@ func (e *FileUploadAndDownloadService) FindOrCreateFile(fileMd5 string, fileName
3949//@description: 创建文件切片记录
4050//@param: id uint, fileChunkPath string, fileChunkNumber int
4151//@return: error
42-
52+ ·
4353func (e * FileUploadAndDownloadService ) CreateFileChunk (id uint , fileChunkPath string , fileChunkNumber int ) error {
4454 var chunk example.ExaFileChunk
4555 chunk .FileChunkPath = fileChunkPath
0 commit comments