Letztes Update 06.08.2003
Da im Internet die Informationen für den Zugriff auf die MySQL Datenbank mit den DBExpress Komponenten sehr verteilt sind, kommt hier mal eine kurze Zusammenfassung.
Fast ohne Probleme. Die Installation klappt auf Anhieb und mit MySQL-Front kann man auch gleich ein wenig herumprobieren. Das schöne an MySQL-Front ist, das bei allen Aktionen die zugehörigen SQL Befehle protokolliert werden. Da kann man immer schön für das eigene Programm abgucken. Ein Problem scheint es jedoch mit dem Administrator von MySQL zu geben. Immer wenn er gelaufen ist, und ich fahre den Rechner runter bekomme ich einen Blue-Screen.
Delphi
MySQL
Zusammanhänge der einzelnen Komponenten:
Folgende Funktionen sind in dem Beispiel enthalten:
Das Testprogramm benötigt zwei Voraussetzungen
1. mylibsql.dll muß in der System32 von Windows liegen. Wenn nicht, dann muß im Programm in sc1.VendorLib der komplette Path angegeben werden.
2. Eine Datenbank mit dem Namen testbase muß vorhanden sein. Die kann z.B. mit MySQL-Front angelegt werden.
Werden Anwendungen weitergegeben, dann sind folgende drei Bibliotheken mit zu liefern:
DbExpMySql.dll
LibMySql.dll
Midas.dll
In Uses-Teil der Interface Sektion müssen folgende Komponenten eingefügt werden:
DB, SqlExpr, FMTBcd, Provider, DBClient, DBLocal, DBLocalS, DBGrids, Grids
Function TForm1.GetEntry:String;
Var sq:String; i:Integer; s1,s2:String;
scs0:TSQLConnection;sds0:TSQLDataSet;dsp0:TDataSetProvider;
cds0:TClientDataSet;tds0:TDataSource;grd0:TDBGrid;
Begin
Result := 'alles klar';
scs0 :=
TSQLConnection.Create(Owner);
sds0 := TSQLDataSet.Create(Owner);
dsp0 :=
TDataSetProvider.Create(Owner);
cds0 :=
TClientDataSet.Create(Owner);
tds0 := TDataSource.Create(Owner);
grd0 := TDBGrid.Create(Owner);
Try
Try
scs0.Name := 'scs0';
scs0.ConnectionName :=
'MSConnection';
scs0.DriverName :=
'MYSQL';
scs0.GetDriverFunc :=
'getSQLDriverMYSQL';
scs0.LibraryName :=
'dbexpmys.dll';
scs0.LoginPrompt :=
false;
scs0.VendorLib :=
'LibMySQL.dll';
sds0.Name := 'sds0';
sds0.SQLConnection :=
scs0;
dsp0.Name := 'dsp0';
dsp0.DataSet :=
sds0;
cds0.Name := 'cds0';
cds0.ProviderName :=
'dsp0';
tds0.Name := 'tds0';
tds0.DataSet :=
cds0;
grd0.Name := 'grd0';
grd0.DataSource :=
tds0;
scs0.Params.Values['Database']
:= 'kunterbunt';
scs0.Params.Values['Hostname']
:= 'localhost';
scs0.Params.Values['User_Name']
:= 'root';
scs0.Params.Values['Password']
:= '';
sq := 'SELECT * FROM
`einfarbig`';
sds0.CommandText :=
sq;
cds0.Active := true;
If cds0.RecordCount > 0 Then
Begin
For i := 1 to
cds0.RecordCount do Begin
s1 :=
grd0.Fields[0].AsString;
s2 :=
grd0.Fields[1].AsString;
cds0.Next;
End;
End;
Except
On E:Exception do
Begin
Result := 'Das war wohl
nix';
End;
End;
If cds0.Active Then cds0.Active :=
false;
Finally
FreeAndNil(grd0);
FreeAndNil(tds0);
FreeAndNil(cds0);
FreeAndNil(dsp0);
FreeAndNil(sds0);
FreeAndNil(scs0);
End;
End;
Es ist darauf zu achten, das der Tabellenname nicht in ' ($27) steht, sondern in ` ($60). Durch dieses Zeichen wird ein Name als Tabellename identifiziert, während ein Name mit ' als String interpretiert wird.
Es ist darauf zu achten, das keine Feldnamen verwendet werden, die mit SQL-Befehlen identisch sind (also kein Feldname der Select heisst). Sollte sich das trotzdem nicht vermeiden lassen, ist der Feldname in `Select` zu setzen.
Die Datenbank arbeitet mit dem Internationalen Datumsformat, d.h. beim Speichern eines Datums muß das Format umgeschaltet werden:
Var sd:String; sp:Char;
Begin
sd := ShortDateFormat;
sp := DateSeparator;
ShortDateFormat := 'YYYY-MM-DD';
DateSeparator := '-';
Try
...
Finally
ShortDateFormat := sd;
DateSeparator := sp;
End;
End;
Wenn jedoch ein Datum in einem Grid angezeigt wird, erscheint es im Rechnerformat (DD.MM.YYYY) und kann auch so eingegeben werden. Ursache unbekannt.
Aufpassen muß man beim Speichern von Float-Zahlen. Im Deutschen ist der Delimeter ein Komma. Ein Komma ist aber auch das Trennungszeichen im INSERT Befehl:
INSERT INTO testtable (Integer1, Real1) VALUES (10, 1,34)
So etwas führt zu der berechtigten Fehlermeldung, das die Anzahl der Argumente nicht korrekt ist.
Wenn eine Float-Zahl in einen String umgewandelt wird, muß als Delimeter ein Punkt eingestellt werden.
Var sd:Char;
Begin
sd := DecimalSeparator;
DecimalSeparator := '.';
Try
...
Finally
DecimalSeparator := sd;
End;
End;
Dann sieht das ganze so aus:
INSERT INTO testtable (Integer1, Real1) VALUES (10, 1.34)
Das Speichern eines binären String funkioniert nicht bei folgenden Typen:
CHAR (x)
CHAR (x) BINARY
VARCHAR (x)
VARCHAR (x) BINARY
TEXT
TINYTEXT
MEDIUMTEXT
LONGTEXT
Unter Delphi kann in einem String jedes Zeichen zwischen $00 und $FF stehen. Zwischen dem INSERT Befehl und dem Speichern in der Datenbanktabelle werden die Zeichen:
$00 = Null, $27 = Esc und $5C = \
einfach geschluckt. Das Backslash kann man noch speichern wenn man es doppelt angibt, bei \\ wird nur ein \ gespeichert. (Überprüft mit einem HEX-Editor).
Wenn man also einen binären String speichern möchte, geht das nur als Stream.
Procedure StrToStream(s1:String;st:TMemoryStream);
begin
st.Write(s1[1],Length(s1));
End;
Function StreamToStr(st:TStream):String;
begin
SetLength(Result,st.Size);
st.Position := 0;
st.Read(Result[1],st.Size);
End;
procedure TMermaid.StringWriteButtonClick(Sender:
TObject);
Var s1,s2:String; x1:TMemoryStream; i:Integer; bf:TBlobField;
Var ts:TStrings;
begin
x1 := TMemoryStream.Create;
s2 := '<';
For i := 0 to 255 do s2 := s2 + Chr(i);
s2 := s2 + '>';
Try
s1 := 'SELECT * FROM `test1`';
SQLDataSet1.CommandText := s1;
Try
ClientDataSet1.Active := true;
bf :=
TBlobField(ClientDataSet1.FieldByName('Str1'));
ClientDataSet1.Edit;
StrToStream(s2,x1);
bf.LoadFromStream(x1);
ClientDataSet1.Post;
ClientDataSet1.ApplyUpdates(0);
ClientDataSet1.Active := false;
Except
On E:Exception do Begin
Logout(E.Message);
End;
End;
Finally
FreeAndNil(x1);
End;
end;
procedure TMermaid.StringReadButtonClick(Sender:
TObject);
Var s1,s2:String; x1:TStream; i:Integer; BlobField:TField;
begin
s1 := 'SELECT * FROM `test1`';
SQLDataSet1.CommandText := s1;
Try
ClientDataSet1.Active := true;
Blobfield := ClientDataSet1.FieldByName('Str1');
x1 :=
ClientDataSet1.CreateBlobStream(BlobField,bmRead);
Try
If ClientDataSet1.FieldByName('Str1').IsNull Then
Begin
Logout('Stream ist leer');
End Else Begin
s2 := StreamToStr(x1);
For i := 1 to Length(s2) do Begin
Logout(IntToHex(Ord(s2[i]),2));
End;
End;
Finally
FreeAndNil(x1);
End;
ClientDataSet1.Active := false;
Except
On E:Exception do Begin
Logout(E.Message);
End;
End;
end;
Die Ursache für den Umstieg auf MySQL liegt in der Abkündigung der BDE. Da die BDE für die Verwaltung von Messwerten benutzt wird, ist eine optimale Lesegeschwindigkeit sehr wichtig. Um optimale Zugriffszeiten auf die Datenbank zu bekommen, wurden diese für einige Komponenten ermittelt:
Gelesen wurden jeweils 10000 Datensätze aus 10 verschiedenen Tabellen. Die folgenden Zeiten ist der Mittelwert aus 100000 Datensätzen.
Paradox Table-Zugriff
Write: 0,25 ms
Save: 3,68 ms
Read: 0,26 ms
Paradox SQL-Zugriff
Write: 4,47 ms
Save: 5,65 ms
Read: 0,07 ms
MySQL DBExpress-Componente, SQL-Zugriff
Write: 0,09 ms
Save: 2,32 ms
Read: 0,09 ms
MySQL ZeosLib Componente, SQL-Zugriff
Write: 14,5 ms
Save: 16,0 ms
Read: 0,49 ms
MySQL DAC Componente, SQL-Zugriff
Write: 2,12 ms
Save: 3,71 ms
Read: 0,38 ms
MySQL CorelLab Components, SQL-Zugriff
Write: 13,7 ms
Save: 24,4 ms
Read: 1,08 ms
Es konnten keine Zeitunterschiede festgestellt werden, zwischen dem Lesen/Schreiben der ersten 10000 Datensätzen und den letzten 10000 Datensätzen.