Curso de dbExpress e DataSnap

Parte XV – Packet Records

Neste exemplo veremos como usar o recurso de Packet Records do ClientDataSet. Configurando essa propriedade, podemos instruir ao servidor de aplicação que “empacote e envie dados por demanda”. Quando temos um grande select no servidor, podemos instruir ao DataSetProvider que vá enviando essas informações aos poucos, para otimizar o tráfego de dados. È importante notar desde já, que essa abordagem é menos escalável: é necessário manter o cursor e conexão ativos durante todo o processo.

Configure uma conexão dbExpress para o banco EMPLOYEE do Interbase. Coloque um SQLConnection apontando para essa conexão. Coloque também um SQLQuery, um DataSetProvider, um ClientDataSet, um DataSource, um DBGrid, um DBNavigator, um Memo e um SQLMonitor. Para configurar o recurso em tempo de execução, coloque também um RadioGroup, dois CheckBoxes, um SpinEdit 

A listagem a seguir mostra como cada componente foi configurado:

 

  object DBGrid1: TDBGrid

    DataSource = DataSource1

  end

  object DBNavigator1: TDBNavigator

    DataSource = DataSource1

  end

  object SQLConnection1: TSQLConnection

    ConnectionName = 'EMPLOYEE'

    DriverName = 'Interbase'

    GetDriverFunc = 'getSQLDriverINTERBASE'

    LibraryName = 'dbexpint.dll'

    LoadParamsOnConnect = True

    LoginPrompt = False

    Params.Strings = (

      'DriverName=Interbase'

      'Database=C:\Borland\InterBase\examples\database\employee.gdb'

      'RoleName=RoleName'

      'User_Name=sysdba'

      'Password=masterkey'

      'ServerCharSet='

      'SQLDialect=3'

      'BlobSize=-1'

      'CommitRetain=False'

      'WaitOnLocks=True'

      'ErrorResourceFile='

      'LocaleCode=0000'

      'Interbase TransIsolation=ReadCommited'

      'Trim Char=False')

    VendorLib = 'gds32.dll'

    Left = 72

    Top = 232

  end

  object SQLQuery1: TSQLQuery

    SQL.Strings = (

      'select * from CUSTOMER')

    SQLConnection = SQLConnection1

  end

  object DataSetProvider1: TDataSetProvider

    DataSet = SQLQuery1

  end

  object ClientDataSet1: TClientDataSet

    ProviderName = 'DataSetProvider1'

  end

  object DataSource1: TDataSource

    DataSet = ClientDataSet1

  end

  object SQLMonitor1: TSQLMonitor

    SQLConnection = SQLConnection1

  end

 

No botão Refresh verificamos as configurações de tela e configuramos o Packet Records do ClientDataSet:

 

procedure TFrmMain.BitBtn2Click(Sender: TObject);

begin

  Memo1.Lines.Clear;

  if CheckBox1.Checked then

    ClientDataSet1.PacketRecords := SpinEdit1.Value

  else

    ClientDataSet1.PacketRecords := -1;

  ClientDataSet1.Close;

  ClientDataSet1.Open;

end;

 

No OnChange do SpinEdit também mudamos essa configuração:

 

procedure TFrmMain.SpinEdit1Change(Sender: TObject);

begin

  ClientDataSet1.PacketRecords := SpinEdit1.Value;

end;

 

No botão GetNextPacket chamamos o método de mesmo nome do ClienDataSet:

 

procedure TFrmMain.BitBtn1Click(Sender: TObject);

begin

  ClientDataSet1.GetNextPacket;

end;

 

No CheckBox com o nome de FetchOnDemand configuramos a propriedade de mesmo do ClienDataSet:

 

procedure TFrmMain.CheckBox2Click(Sender: TObject);

begin

  BitBtn1.Enabled := not CheckBox2.Checked;

  ClientDataSet1.FetchOnDemand := CheckBox2.Checked;

end;

 

No CheckBox usar PacketRecords fazemos alguns ajustes visuais:

 

procedure TFrmMain.CheckBox1Click(Sender: TObject);

var

  i : integer;

begin

  GroupBox1.Enabled := CheckBox1.Checked;

  Label1.Enabled := CheckBox1.Checked;

  SpinEdit1.Enabled := CheckBox1.Checked;

  CheckBox2.Enabled := CheckBox1.Checked;

  BitBtn1.Enabled := (CheckBox1.Checked) and not (CheckBox2.Checked);

end;

 

No evento OnLogTrace do SQLMonitor vamos monitorar a comunicação com o IB/FB para verificar quando e quais comandos estão sendo executados, jogando essas informações para um Memo:

 

procedure TFrmMain.SQLMonitor1LogTrace(Sender: TObject;

  CBInfo: pSQLTRACEDesc);

begin

  Memo1.Lines.Add(String(CBInfo.pszTrace));

end;

 

Vamos executar a aplicação e fazer alguns testes, usando diferentes configurações. Dessa forma, vamos entender exatamente como o PacketRecords funciona.

 

1 – Sem usar PacketRecords - clique no botão Refresh e veja o comportamento na figura a seguir. Todos os dados retornados pelo Select foram empacotados e jogados na memória (Data) do ClienDataSet. Nenhum recurso do servidor, incluindo conexão e cursor, fica preso. No entanto, o tempo necessário e tráfego de rede usado para transferir o packet é maior.

 

2 – Usando PacketRecords com FetchOnDemand ativado - clique no botão Refresh e veja o comportamento na figura a seguir. Configuramos o packet size como “3”, o que indica que os registros serão empacotados de 3 em três. O próprio ClientDataSet detecta quando mais registros são necessário e traz por demanda (daí o nome FetchOnDemand). Isso pode acontecer tanto por necessidade do usuário (confirme isso navegando no DBGrid para baixo) ou programaticamente (via chamadas subseqüentes ao método Next). Observe que cada Fetch envolve, lógico, uma chamada ao servidor SQL. A solução é mais otimizada para grandes resultsets, mais vai consumir mais recursos do BD, pois o cursor e conexão ficam presos aguardando novas solicitações de packet.

 

3 – Usando PacketRecords com FetchOnDemand desativado - clique no botão Refresh e veja o comportamento na figura a seguir. Configuramos o packet size como “3”, o que indica que os registros serão empacotados de 3 em três. A diferença em não usar o FetchOnDemand é que você deve solicitar novos pacotes de dados, através do método GetNextPacket do CDS (fizemos isso no botão). Faça um teste navegando até o último registro do DBGrid, observe que ele “trava” no terceiro. Clicando no botão GetNextPacket, mais três registros serão trazidos. Cada Fetch envolve, lógico, uma chamada ao servidor SQL. A solução é mais otimizada para grandes resultsets, mais vai consumir mais recursos do BD, pois o cursor e conexão ficam presos aguardando novas solicitações de packet.

 

 

Download

Leia todos artigos da série