多次调用FireDac FDQuery触发访问违例问题求助
解决FDQuery多次调用触发访问违例的问题
问题根源分析
你的访问违例大概率来自以下几个未正确处理的资源管理问题:
1. BlobStream未释放
在ConvertData中,通过queryObj.CreateBlobStream创建的commentsBlob、dataBlob、attrBlob没有被手动释放。这些流对象由FDQuery实例持有引用,若不释放,会导致内存泄漏,且后续循环中创建新FDQuery时,旧的无效引用会干扰新对象的操作,引发AV。
2. 提前Exit导致Query未关闭
在ConvertData的查询执行块中,当Recordcount=0或捕获到异常时直接调用Exit,此时FDQuery仍处于打开状态。后续在外部循环中释放FDQuery时,关闭未完成的查询会触发对象状态异常。
3. 异常处理的覆盖问题
ConvertData内部的异常捕获仅弹出提示就Exit,没有确保资源被清理,也没有将异常传递到外部,导致外部循环无法感知内部错误,继续执行后引发更严重的AV。
修复方案
针对上述问题,修改ConvertData的关键代码部分:
修复BlobStream的释放
在复制Blob数据后,立即释放对应的BlobStream:
// Copy blob data to memory streams commentsBlob := queryObj.CreateBlobStream(queryObj.FieldByName('col4'), bmRead); if assigned(commentsBlob) then try commentsStream.CopyFrom(commentsBlob, queryObj.FieldByName('col1').AsInteger); finally commentsBlob.Free; // 释放BlobStream end; dataBlob := queryObj.CreateBlobStream(queryObj.FieldByName('col5'), bmRead); if assigned(dataBlob) then try dataStream.CopyFrom(dataBlob, queryObj.FieldByName('col2').AsInteger); finally dataBlob.Free; end; attrBlob := queryObj.CreateBlobStream(queryObj.FieldByName('col6'), bmRead); if assigned(attrBlob) then try attrStream.CopyFrom(attrBlob, queryObj.FieldByName('col3').AsInteger); finally attrBlob.Free; end;
确保Query始终被关闭
调整ConvertData中查询执行的逻辑,无论是否有记录或异常,都确保Query被关闭:
with queryObj do begin SQL.Text := 'SELECT col1, col2, col3, col4, col5, col6 FROM ' + tableName + ' WHERE dateColumn=:param1 AND siteColumn=:param2'; ParamByName('param1').AsDate := dateParam; ParamByName('param2').AsInteger := siteID; try Open; if (Recordcount = 0) then Exit; // 提前退出前确保后续会执行Close except on E: Exception do begin ShowMessage('Error executing query: ' + E.Message); Exit; end; end; end; // 用try-finally包裹后续处理,确保Query最终被关闭 try // 原有的流处理、数组转换等代码放这里 finally queryObj.Close; end;
优化异常处理
将ConvertData内部的异常改为重新抛出,让外部循环能够捕获并终止,避免无效的后续执行:
except on E: Exception do begin ShowMessage('Error in ConvertData: ' + E.Message); raise; // 重新抛出异常,让外部循环处理 end; end;
额外建议
- 避免在循环中频繁创建和释放FDQuery,可以复用一个FDQuery实例,每次循环前清空SQL、参数并重新执行,减少对象创建销毁的开销和潜在的资源问题。
- 所有资源操作都用
try-finally包裹,确保任何情况下资源都能被正确释放。
内容的提问来源于stack exchange,提问作者Surox
相关产品推荐
相关产品推荐

