「11.Lazarus数据库编程」14.在控制台程序中使用ZeosDBO

14.在控制台程序中使用ZeosDBO

控制台程序中操作数据库也可以使用 ZeosDBO 组件,这样极大地帮助我们在编写数据预处理程序中使用 ZeosDBO。

14.1在控制台程序中使用 ZeosDBO 的一些设置

首先,在 Lazarus 中,我们选择 Project -> New Project,在新建项目的对话框中选择 Program,然后单击 Ok,创建控制台程序。

然后,选择 Project -> Inspector,打开 Project Inspector 对话框,右击 Required Packages,选择 Add,如下图:

「11.Lazarus数据库编程」14.在控制台程序中使用ZeosDBO

然后在右侧的列表中找到 zcomponent,选择并单击 Ok。

这时,我们编译应用程序,可能会出现:

laz1113.lpr(13,1) Error: Undefined symbol: WSRegisterCustomPage

类似的错误提示,在这种情况下,我们在应用程序的 uses 中删除如下单元:

zcomponent

经过上面的设置后,我们的控制台应用程序中就可以使用 ZeosDBO 组件。

在应用程序中一般会需要 uses 如下单元:

SysUtils

14.2 控制台程序使用 ZeosDBO 组件

示例1:通过控制台程序在某 PostgreSQL 数据库上执行 select 语句。

数据准备:

drop table if exists d_phone;

create table d_phone(
  phone_id serial primary key,
  name varchar(32),
  phone_number varchar(64)
);

INSERT INTO public.d_phone
(name, phone_number)
VALUES('张三', '0471-2336789');
INSERT INTO public.d_phone
(name, phone_number)
VALUES('李四', '0471-3338976');
INSERT INTO public.d_phone
(name, phone_number)
VALUES('王五', '0471-3627898');
INSERT INTO public.d_phone
(name, phone_number)
VALUES('赵六', '0471-3678901');
INSERT INTO public.d_phone
(name, phone_number)
VALUES('周七', '0471-3601989');

示例代码:

program laz1113;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes, SysUtils, ZConnection, ZSQLMonitor, ZDataSet, DB
  { you can add units after this };

var
  ZPGConnection: TZConnection;
  ZPGSQLMonitor: TZSQLMonitor;
  Query: TZQuery;
  sSQL: String;

begin
  ZPGConnection := TZConnection.Create(nil);
  ZPGConnection.Protocol:='postgresql-9';
  ZPGConnection.HostName:='127.0.0.1';
  ZPGConnection.Port:=9432;
  ZPGConnection.User:='postgres';
  ZPGConnection.Password:='***';
  ZPGConnection.Database:='demodb';

  try
    ZPGConnection.Connected:=True;

    ZPGSQLMonitor:=TZSQLMonitor.Create(nil);
    ZPGSQLMonitor.FileName:='trace.log';
    ZPGSQLMonitor.AutoSave:=True;
    ZPGSQLMonitor.Active:=True;

    Query:=TZQuery.Create(nil);
    Query.Connection:=ZPGConnection;
    sSql:='select cast(gen_random_uuid() as text) as uuid';
    Query.SQL.Clear;
    Query.SQL.Text:=sSql;
    Query.Prepare;
    Query.Active:=True;
    while not Query.EOF do
    begin
      Writeln(Query.FieldByName('uuid').AsString);
      Query.Next;
    end;

    sSql := 'SELECT name, phone_number FROM d_phone';
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Text:=sSql;
    Query.Prepare;
    Query.Active:=True;
    while not Query.EOF do
    begin
      Writeln(Query.FieldByName('name').AsString + ' -> ' + Query.FieldByName('phone_number').AsString);
      Query.Next;
    end;
    Query.Destroy;

    ZPGConnection.Connected:=False;
  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
  end;

  ZPGConnection.Destroy;
end.

F9 运行程序,输出如下:

b6aa0849-3ac8-4dae-8ade-bba66ab11a3e
张三 -> 0471-2336789
李四 -> 0471-3338976
王五 -> 0471-3627898
赵六 -> 0471-3678901
周七 -> 0471-3601989

trace.log 文件内容:

2022-06-19 16:58:44 cat: Prepare, proto: postgresql-9, msg: Statement 1 : select cast(gen_random_uuid() as text) as uuid

2022-06-19 16:58:44 cat: Execute prepared, proto: postgresql-9, msg: Statement 1
2022-06-19 16:58:44 cat: Prepare, proto: postgresql-9, msg: Statement 2 : SELECT name, phone_number FROM d_phone

2022-06-19 16:58:44 cat: Execute prepared, proto: postgresql-9, msg: Statement 2
2022-06-19 16:58:44 cat: Prepare, proto: postgresql-9, msg: Statement 3 : SELECT n.nspname,c.relname,a.attname,case t.typtype when 'd' then t.typbasetype else t.oid end as atttypid,case t.typtype when 'd' then t.typnotnull else a.attnotnull end as attnotnull,case t.typtype when 'd' then t.typtypmod else a.atttypmod end as atttypmod,case t.typtype when 'd' then t.typlen else a.attlen end as attlen,a.attnum,pg_get_expr(def.adbin, def.adrelid) as adsrc,dsc.description, dn.nspname as cnspname, case t.typtype when 'd' then t.oid else null end as domain_oid FROM pg_catalog.pg_namespace n  JOIN pg_catalog.pg_class c ON (c.relnamespace = n.oid)  JOIN pg_catalog.pg_attribute a ON (a.attrelid=c.oid)  JOIN pg_catalog.pg_type t ON (t.oid = a.atttypid) LEFT JOIN pg_catalog.pg_attrdef def ON (a.attrelid=def.adrelid AND a.attnum = def.adnum) LEFT JOIN pg_catalog.pg_description dsc ON (c.oid=dsc.objoid AND a.attnum = dsc.objsubid)  LEFT JOIN pg_catalog.pg_class dc ON (dc.oid=dsc.classoid AND dc.relname='pg_class')  LEFT JOIN pg_catalog.pg_namespace dn ON (dc.relnamespace=dn.oid AND dn.nspname='pg_catalog')  WHERE a.attnum > 0 AND c.oid = 18736 ORDER BY nspname,relname,attnum
2022-06-19 16:58:44 cat: Execute prepared, proto: postgresql-9, msg: Statement 3
2022-06-19 16:58:44 cat: Execute, proto: postgresql-9, msg: SELECT oid, typname, typbasetype,typtype FROM pg_type WHERE (typtype = 'b' and oid < 10000) OR typtype = 'p' OR typtype = 'e' OR typbasetype<>0 ORDER BY oid
2022-06-19 16:58:44 cat: Other, proto: Postgres NOTICE, msg: WARNING:  there is no transaction in progress

2022-06-19 16:58:44 cat: Transaction, proto: postgresql-9, msg: COMMIT
2022-06-19 16:58:44 cat: Disconnect, proto: postgresql-9, msg: DISCONNECT FROM "demodb"

示例2:基于上面的数据表,开发一个文本模式下的数据增删改查程序。

示例代码:

program laz1114;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes, SysUtils, ZConnection, ZDataSet, ZSQLMonitor, DB
  { you can add units after this };

var
  PGConnection: TZConnection;
  PGSQLMonitor: TZSQLMonitor;
  Command: Integer;

procedure Select;
var
  Query: TZQuery;
  sSql: String;
begin
  sSql := 'SELECT phone_id, name, phone_number FROM d_phone';
  Query := TZQuery.Create(nil);
  try
    Query.Connection:=PGConnection;
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Text := sSql;
    Query.Prepare;
    Query.Open;
    while not Query.EOF do
    begin
      Writeln(Query.FieldByName('phone_id').AsString + ' ' +
              Query.FieldByName('name').AsString + ' ' +
              Query.FieldByName('phone_number').AsString);
      Query.Next;
    end;
  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
  end;
  Query.Destroy;
end;

procedure Insert;
var
  Query: TZQuery;
  sSql: String;
  name: String;
  PhoneNumber: String;
begin
  Writeln('Please input name:');
  Readln(name);
  Writeln('Please input phone number:');
  Readln(PhoneNumber);

  sSql := 'INSERT INTO d_phone(name, phone_number) VALUES (:name, :PhoneNumber)';
  Query := TZQuery.Create(nil);
  try
    Query.Connection:=PGConnection;
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Text := sSql;
    Query.Params.ParamByName('name').AsString:=name;
    Query.Params.ParamByName('PhoneNumber').AsString:=PhoneNumber;
    Query.Prepare;
    Query.ExecSQL;
  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
  end;
  Query.Destroy;
end;

procedure Update;
var
  Query: TZQuery;
  sSql: String;
  PhoneId: Integer;
  name: String;
  PhoneNumber: String;
begin
  Select;
  Writeln('Please input phone id:');
  Readln(PhoneId);
  Writeln('Please input name:');
  Readln(name);
  Writeln('Please input phone number:');
  Readln(PhoneNumber);

  sSql := 'UPDATE d_phone set name=:name, phone_number=:PhoneNumber WHERE phone_id=:PhoneId';
  Query := TZQuery.Create(nil);
  try
    Query.Connection:=PGConnection;
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Text := sSql;
    Query.Params.ParamByName('name').AsString:=name;
    Query.Params.ParamByName('PhoneNumber').AsString:=PhoneNumber;
    Query.Params.ParamByName('PhoneId').AsInteger:=PhoneId;
    Query.Prepare;
    Query.ExecSQL;
  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
  end;
  Query.Destroy;
end;

procedure Delete;
var
  Query: TZQuery;
  sSql: String;
  PhoneId: Integer;
begin
  Select;
  Writeln('Please input phone id:');
  Readln(PhoneId);

  sSql := 'DELETE FROM d_phone WHERE phone_id=:PhoneId';
  Query := TZQuery.Create(nil);
  try
    Query.Connection:=PGConnection;
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Text := sSql;
    Query.Params.ParamByName('PhoneId').AsInteger:=PhoneId;
    Query.Prepare;
    Query.ExecSQL;
  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+sSql+chr(13)+chr(10)+E.ClassName+chr(13)+chr(10)+E.Message);
  end;
  Query.Destroy;
end;

begin
  PGConnection := TZConnection.Create(nil);
  PGConnection.Protocol:='postgresql-9';
  PGConnection.HostName:='127.0.0.1';
  PGConnection.Port:=9432;
  PGConnection.User:='postgres';
  PGConnection.Password:='***';
  PGConnection.Database:='demodb';

  try
  PGConnection.Connected:=True;

  PGSQLMonitor:=TZSQLMonitor.Create(nil);
  PGSQLMonitor.FileName:='trace.log';
  PGSQLMonitor.AutoSave:=True;
  PGSQLMonitor.Active:=True;

  except
     on E: EDatabaseError do
       Writeln('DB ERROR: '+E.ClassName+chr(13)+chr(10)+E.Message);
     on E: Exception do
       Writeln('ERROR: '+E.ClassName+chr(13)+chr(10)+E.Message);
  end;

  while True do
  begin
    Writeln('Please select:');
    Writeln('0-Exit');
    Writeln('1-Select');
    Writeln('2-Insert');
    Writeln('3-Update');
    Writeln('4-Delete');

    Readln(Command);

    case Command of
      0: Break;
      1: Select;
      2: Insert;
      3: Update;
      4: Delete;
      else
        Writeln('Please input 0-4');
    end;
  end;

  PGConnection.Destroy;

end.

F9 运行程序:

Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
1
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
2
Please input name:
林十一
Please input phone number:
0471-5922873
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
1
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
8 林十一 0471-5922873
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
3
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
8 林十一 0471-5922873
Please input phone id:
8
Please input name:
秦十二
Please input phone number:
0471-5922873
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
1
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
8 秦十二 0471-5922873
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
4
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
8 秦十二 0471-5922873
Please input phone id:
8
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
1
1 张三 0471-2336789
2 李四 0471-3338976
3 王五 0471-3627898
4 赵六 0471-3678901
5 周七 0471-3601989
7 刘八 0471-2233199
6 姜九 0471-2233559
Please select:
0-Exit
1-Select
2-Insert
3-Update
4-Delete
0

14.3 Linux环境下运行控制台程序

要在 Linux 环境下运行 Lazarus 编写的程序,需要在 Linux 环境下搭建 Lazarus 开发环境并安装 ZeosDBO,搭建开发环境也是比较耗时的一件事情,我们可以选择 CodeTyphon 作为 Linux 环境下的开发环境,CodeTyphon 是一个免费的Pascal语言可视化编程工作室软件包,基于 Free Pascal 和 Lazarus。相当于Delphi 的RAD Studio。

CodeTyphon支持多平台开发,包括多平台的编译器、RAD IDE和调试器,并集成了大量的组件包(包括源码)。支持32位和64位开发,并可以进行跨平台的交叉编译。

CodeTyphon提供控制中心,完成平台编译、安装控制、组件包控制、交叉编译。还包括一些其它的工具。

在 CodeTyphon 环境下创建应用程序并编写上面的代码(可以直接复制代码),然后编译运行即可。注意代码中 uses 语句中的单元名在 Linux 环境下是区分大小写的。如上面的代码中:

Classes, SysUtils, ZConnection, ZDataSet, ZSQLMonitor, DB

在 Linux 环境下要写成:

Classes, SysUtils, ZConnection, ZDataset, ZSqlMonitor, DB

另外在运行程序时,由于使用 PostgreSQL 数据库,所以需要动态链接库,在执行程序前需要设置环境变量:

LD_LIBRARY_PATH=/usr/local/pgsql/lib
export LD_LIBRARY_PATH



发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章