Problemas com DataSnap 2010
Olá pessoal ...
To com um problema na utilização do DataSnap do D2010.
Eu migrei um dos meus sistemas que era em D7 para D2010, eu
utilizava Multi-Camadas no D7, mas resolvi optar por usar a nova tecnologia do
DataSnap. Até ai tudo bem, só que depois que coloquei na linha de produção
comecei a ter alguns problemas, que eu não tinha, as vezes o meu sistema
tentava pegar uma informação do banco de dados e não encontrava, me dava a
mensagem “Can not open a Resultset”, ( eu uso PostgresSQL 8.4, com Zeos 7 ), entre outras mensagens, eu olhava no meu log,
tinha SQL correto, que não conseguia ser executado. Como disse não tinha esse
problema ... Ontem fiz um pequeno Sistema só para testar a minha conexão ... O
que eu fiz .
Criei um Servidor com a estrutura parecida com que eu
utilizo em linha de produção basicamente é isto Criei DataModulo, e um DSServerModule,
no meu DataModule coloquei o componente DSServer, um DSTCPServerTransport, um
DSServerClass e um ZConnection, o meu DSServerClass esta com a propriedade
LifeCycle = Session, até aqui ok .... no meu DSServerModule criei três funções.
function
GetTime: String; // Só faz pegar a hora.
function RunSQL(lcSQL: String): boolean; //
Vai Executar um Update ou Insert
function
SQLToStr(lcSQL: String): String; // Retorna um Select, não um bloco só um
campo.
Criei um Sistema Cliente, que pega essa data, executa um insert,
pega o SELECT, conecta e disconecta ...
tem um time que executa isto ...
Ontem anoite deixei rolando . abri o Servidor abri quatro
desses clientes ... para cada um fazer uma dessas funções ... coloquei o time
para 2 segundos ... olhei de manhã e nenhum erro ...
Fiz outro teste colocando o time para meio segundo . começou
os problemas ... esses erros que
comentei de não poder abrir o ResultSet .... falta de Sincronismo com o banco .
a ponto de desconectar o meu Servidor ... mesmo com os erros tratados ...
perdeu a conexão, tendo que abrir um novo servidor, aumentei para 1 segundo, o
servidor não travou ... mas de vez enquando o SELECT não era retornado ...
quando abria mas de um Sistema Cliente ... para pegar o SELECT na mesma tabela,
quando eu abri quatro ... somente para o SELECT voltei a ter problema deu este
erro “SQL Error: message contents do not agree with length in message type
"T"
server sent
data ("D" message) without prior row description ("T"
message)”.
E não consegui mas manipular as minhas funções de acesso a
banco.
Não sei se estou configurando algo errado ... ou onde esta
este problema ...
Fico esperando a ajuda de vcs.
Jardson Cleyton
Curtidas 0
Respostas
Jardson Cleyton
28/04/2010
Vou mandar o Codigo das Units que criei tanto no Servidor
como no Cliente ...
SERVIDOR
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, AppEvnts;
type
TForm1 = class(TForm)
mmoError: TMemo;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
end.
unit
Useful;
interface
uses
ZConnection, Dialogs, SysUtils, DB, ZDataSet;
type
TUseful = class
strict private
class var FoConn: TZConnection;
class procedure SetConn(loConn:
TZConnection);
public
class function GetConn: TZConnection;
class function ConnectDataBase(loConn:
TZConnection): boolean;
class function RunSQL(lcSQL: String):
Boolean;
class function SQLToStr(lcSQL: String):
String;
end;
implementation
uses Main;
{ TUseful }
class
function TUseful.ConnectDataBase(loConn: TZConnection): boolean;
begin
try
loConn.Database := 'jcs_bdsge';
loConn.User := 'postgres';
loConn.Password := '761270';
loConn.Port := 5432;
loConn.Protocol :=
'postgresql-8';
loConn.HostName := '192.168.1.201';
loConn.Connected := true;
SetConn(loConn);
result := true;
except on e: exception do
begin
raise EDatabaseError.Create(loConn.Database
+ #13#10 +
loConn.User + #13#10 +
loConn.Password + #13#10 +
IntToStr(loConn.Port) + #13#10
+
loConn.Protocol + #13#10
+
loConn.HostName + #13#10 +
e.Message);
end;
end;
end;
class
function TUseful.GetConn: TZConnection;
begin
if FoConn <> nil
then Result := FoConn
else raise EDataBaseError.Create('Conexão
inválida');
end;
class
function TUseful.RunSQL(lcSQL: String): Boolean;
begin
if GetConn.ExecuteDirect(lcSQL)
then result := true
else begin
result := false;
form1.mmoError.Lines.Add(DateToStr(Date) + ' ' + TimeToStr(Time));
form1.mmoError.Lines.Add('Message : Erro ao tentar inserir ' + lcSQL);
form1.mmoError.Lines.Add('----------------------------------------------------------'
+
'----------------------------------------------------------------');
end;
end;
class
procedure TUseful.SetConn(loConn: TZConnection);
begin
FoConn := loConn;
end;
class
function TUseful.SQLToStr(lcSQL: String): String;
var
loQry: TZQuery;
begin
loQry := TZQuery.Create(nil);
loQry.Connection := GetConn;
loQry.Close;
loQry.SQL.Clear;
loQry.SQL.Add(lcSQL);
try
loQry.Open;
result := loQry.Fields[0].AsString;
except on e: Exception do
begin
result := '';
form1.mmoError.Lines.Add(DateToStr(Date)
+ ' ' + TimeToStr(Time));
form1.mmoError.Lines.Add('Message : ' + E.Message);
form1.mmoError.Lines.Add('ClassName: ' +
E.ClassName);
form1.mmoError.Lines.Add('----------------------------------------------------------'
+
'----------------------------------------------------------------');
end;
end;
FreeAndNil(loQry);
end;
end.
unit
DModule;
interface
uses
SysUtils, Classes, DSCommonServer, DSServer,
DSTCPServerTransport, ZConnection, Forms;
type
TDataModule2 = class(TDataModule)
DSTCPSTSGE: TDSTCPServerTransport;
DSSSGE: TDSServer;
DSServerClass1: TDSServerClass;
procedure
DSServerClass1GetClass(DSServerClass: TDSServerClass;
var PersistentClass: TPersistentClass);
private
{ Private declarations }
public
{ Public declarations }
end;
var
DataModule2: TDataModule2;
implementation
uses
Useful, SMMainClass;
{$R *.dfm}
procedure
TDataModule2.DSServerClass1GetClass(DSServerClass: TDSServerClass;
var PersistentClass: TPersistentClass);
begin
PersistentClass := TDSServerModule1;
end;
end.
unit
SMMainClass;
interface
uses
SysUtils, Classes, DSServer, ZConnection;
type
TDSServerModule1 = class(TDSServerModule)
ZConJCS_BDSGE: TZConnection;
procedure DSServerModuleCreate(Sender:
TObject);
private
public
function GetTime: String;
function RunSQL(lcSQL: String): boolean;
function SQLToStr(lcSQL: String): String;
end;
implementation
uses
Useful;
{$R *.dfm}
{
TDSServerModule1 }
procedure
TDSServerModule1.DSServerModuleCreate(Sender: TObject);
begin
TUseful.ConnectDataBase(ZConJCS_BDSGE);
end;
function
TDSServerModule1.GetTime: String;
begin
result := TimeToStr(Time);
end;
function
TDSServerModule1.RunSQL(lcSQL: String): boolean;
begin
result := TUseful.RunSQL(lcSQL);
end;
function
TDSServerModule1.SQLToStr(lcSQL: String): String;
begin
result := TUseful.SQLToStr(lcSQL);
end;
end.
Como eu disse é uma
aplicação simples ... no Servidor só tem essas quatro units ... e como foi
sugerido pelo Bruno coloquei o meu conector de banco no ServerModule.
APLICAÇÃO CLIENTE
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, WideStrings, DbxDatasnap, DB,
SqlExpr, StdCtrls, ExtCtrls;
type
TOption = (opCatchDate, opInsert, opSelect,
opConnection);
TForm2 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
SQLConnection1: TSQLConnection;
Timer1: TTimer;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
FoOption : TOption;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses
ClassProxy;
{$R *.dfm}
procedure
TForm2.Button1Click(Sender: TObject);
begin
FoOption := opCatchDate;
Timer1.Enabled := true;
end;
procedure
TForm2.Button2Click(Sender: TObject);
begin
FoOption := opInsert;
Timer1.Enabled := true;
end;
procedure
TForm2.Button3Click(Sender: TObject);
begin
FoOption := opSelect;
Timer1.Enabled := true;
end;
procedure
TForm2.Button4Click(Sender: TObject);
begin
FoOption :=
opConnection;
Timer1.Enabled :=
true;
end;
procedure
TForm2.Timer1Timer(Sender: TObject);
var
loClass :
TDSServerModule1Client;
lcSQL, lcTemp:
String;
begin
if not SQLConnection1.Connected
then SQLConnection1.Connected := true;
loClass :=
TDSServerModule1Client.Create(SQLConnection1.DBXConnection);
case FoOption of
opCatchDate : Memo1.Lines.Add('Hora : ' + loClass.GetTime);
opInsert : begin
lcSQL := 'INSERT INTO
TSGETES (TES_VAL) VALUES (' + QuotedStr(TimeToStr(Time)) + ')';
Memo1.Lines.Add('Insert : '
+ BoolToStr(loClass.RunSQL(lcSQL)) + ' | ' + lcSQL);
end;
opSelect
: Memo1.Lines.Add('Select : ' + loClass.SQLToStr('SELECT MAX(TES__ID)
FROM TSGETES'));
opConnection: if SQLConnection1.Connected =
true
then begin
SQLConnection1.Connected
:= false;
try
SQLConnection1.Connected
:= true;
Memo1.Lines.Add('Conectar : Conectado com sucesso! ' + TimeToStr(Time));
except on e :
exception do
Memo1.Lines.Add('Conectar
: Erro ao tentar conectar | ' + TimeToStr(Time) + ' '+ e.Message);
end;
end;
end;
FreeAndNil(loClass);
end;
end.
Essa Aplicação só tem uma unit mesmo e a unit gerado pelo
SQLConnection para minha conexão com o DataSnap.
GOSTEI 0