各们大虾:在下在开发中碰到一个问题,就是如何高效存取SQL Server 2000中BLOB字段。请各位高手赐教。
问题背景:在开发基于SQL Server 2000的一个传统c/S数据库应用程序时,一个用户表中有多个image(即BLOB)类型的字段(现以三个字段bFacePhoto、bSidePhoto、bAllPhoto来说明问题),用于存放三幅图(JPG格式的,已经过减肥,每幅图大小不等,最小的45KB,最大的100多KB),存取现在都是没有问题的,问题的核心是在取出相应的记录时,有相当的延时。我用的是开发工具是delphi 7,用ADO访问数据库,现在我想加入ClientDataSet和DataSetProvider,并设置DataSetProvider 的poFetchBlobsOnDemand为True,想利用这个缓冲数据集在解决读取图像时严重延时的问题,我想在列记录时先不取出BLOB信息,等用户想查看图像时,就再读取相应记录的BLob信息,我调用了Fill_Picture(DataSet)过程完成图像读取,代码如下:
procedure TFrmNew.Fill_Picture(DataSet: TDataSet);
var
  sFileName1, sFileName2, sFileName3: string;
  tempstream1, tempstream2, tempstream3: TStringStream;
  tempjpeg1, tempjpeg2, tempjpeg3: TJPEGImage;
begin
  if not DataSet.IsEmpty then
  begin
    try
      tempstream1 := TStringStream.Create(' ');
      tempstream2 := TStringStream.Create(' ');
      tempstream3 := TStringStream.Create(' ');      if (not Dataset.FieldByName('bFacePhoto').IsNull) then
      begin
        TBlobField(Dataset.FieldByName('bFacePhoto')).SaveToStream(tempstream1);
        tempstream1.Position := 0;
        if not Assigned(tempjpeg1) then
          tempjpeg1 := TJPEGImage.Create;
        tempjpeg1.LoadFromStream(tempstream1);
        Img1.Picture.Bitmap.Assign(tempjpeg1);
        sFileName1 := ExtractFilePath(Application.ExeName) + 'tmpFaceBlob';
        sFileName1 := sFileName1 + '.Jpg';
        img1.Picture.SaveToFile(sFileName1);
      end
      else
      begin
        Img1.Picture.Graphic := nil; //清空正面照图像
      end;
      if (not Dataset.FieldByName('bSidePhoto').IsNull) then
      begin
        TBlobField(Dataset.FieldByName('bSidePhoto')).SaveToStream(tempstream2);
        tempstream2.Position := 0;
        if not Assigned(tempjpeg2) then
          tempjpeg2 := TJPEGImage.Create;
        tempjpeg2.LoadFromStream(tempstream2);
        Img2.Picture.Bitmap.Assign(tempjpeg2);
        sFileName2 := ExtractFilePath(Application.ExeName) + 'tmpSideBlob';
        sFileName2 := sFileName2 + '.Jpg';
        img2.Picture.SaveToFile(sFileName2);
      end
      else
      begin
        Img2.Picture.Graphic := nil; //清空侧面照图像
      end;
      if (not Dataset.FieldByName('bAllPhoto').IsNull) then
      begin
        TBlobField(Dataset.FieldByName('bAllPhoto')).SaveToStream(tempstream3);
        tempstream3.Position := 0;
        if not Assigned(tempjpeg3) then
          tempjpeg3 := TJPEGImage.Create;
        tempjpeg3.LoadFromStream(tempstream3);
        Img3.Picture.Bitmap.Assign(tempjpeg3);
        sFileName3 := ExtractFilePath(Application.ExeName) + 'tmpAllBlob';
        sFileName3 := sFileName3 + '.Jpg';
        img3.Picture.SaveToFile(sFileName3);
      end
      else
      begin
        Img3.Picture.Graphic := nil; //清空全身照图像
      end;
      OleContainer1.Visible := False;
    finally
      if sFileName1 <> '' then deleteFile(sfileName1);
      if sFileName2 <> '' then deleteFile(sfileName2);
      if sFileName3 <> '' then deleteFile(sfileName3);
      if Assigned(tempjpeg1) then
        tempjpeg1.Free;
      if Assigned(tempjpeg2) then
        tempjpeg2.Free;
      if Assigned(tempjpeg3) then
        tempjpeg3.Free;      tempstream1.Free;
      tempstream2.Free;
      tempstream3.Free;
    end;
  end;
end;
因此我在ClientDataSet的AfterScroll中:
procedure TFrmNew.ClientDataSet1AfterScroll(DataSet: TDataSet);
begin
  Fill_Picture(DataSet);
end;但问题出来了,设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,但我想在用户在DBGridEh1中移动光标定位到下一行时就取出图像,其实是不应该在ClientDataSet1AfterScroll中调用Fill_Picture 的,因为这样一旦ClientDataSet1.Open后就会执行Fill_Picture, 如果不在ClientDataSet1AfterScroll中调用Fill_Picture 请问我该如何做?谢谢了。

解决方案 »

  1.   

    请各位极积发言,分不够可以加,再下还想由此引了一个关于使用ClientDataSet的讨论。愿意听到各位高手的高见.
      

  2.   

    我觉得可以像这样:
    你在BeforeOpen、OnClose事件中写 ClientDataSet1.OnAfterScroll:=nil;在AfterOpen事件中写 ClientDataSet1.OnAfterScroll:=Fill_Picture;
      

  3.   

    问题是我只要一设置DataSetProvider 的poFetchBlobsOnDemand为True时出现了错误"Blob has not been fetched",即BLOB字段在此时是没有被取回来的,我如何通过ClientDataSet1.FetchBlobs来取得
    BLOB型字段,另外楼主所说的 ClientDataSet1.OnAfterScroll := nil;这样不行啊,编译都通不过。
      

  4.   

    如果图象不太大的话,最好使用MemoStream来加速。
    我在我的系统中存储的文件大小基本上是5MB左右的,在响应时间一般为0.3秒;如果用stringStream的话要1.1秒左右。当然,你的内存要大点才好。