Tampilkan postingan dengan label free pascal. Tampilkan semua postingan
Tampilkan postingan dengan label free pascal. Tampilkan semua postingan

Selasa, 14 November 2023

Creating A Thread Safe Database Connection Pool for Delphi and Free Pascal based Lazarus

One day I got a software project to create an application that need to be accessed from many computer with one data server. I decided to create a three-tier application, a client application for the client computer and a middle application that connect directly to database server that is a Firebird Database Server for this project. After a few weeks the project is finished and I realized that the response time of every client request is very slow caused by database connection time. Because every time client request arrived the middle application create new thread to handle the request and create new database connection and doing database query and then send the respond data back to the requester client and finally close database connection and free database connection, transaction and queries objects before the thread is destroyed.

Then I begin researching to reduce the database connection time in the request handler thread. I become pesimistic after I read in delphi manual book that every thread must create and use its own database connection. But I'm still not giving up because other programming like PHP and MySQL can do that. Then I try to isolate every parts of the database connection and database query in part by part, and finally I'm able to reuse database connection, transcation and query object with many threads by isolating creation and desctruction of database connection object and transaction object and also commit and rollback process, everything else is no problem with multithread.

  1. procedure TSimpleQuery.Commit;
  2. begin
  3.   if ((FQuery.Connection = nil) or not FQuery.Connection.Connected or
  4.     FQuery.Connection.AutoCommit) then exit;
  5.   EnterCriticalSection(FConnectionManager.GetCriticalSection^);
  6.   try
  7.     try
  8.       FQuery.Connection.Commit;
  9.     except
  10.       LogExceptionMessage;
  11.       raise;
  12.     end;
  13.   finally
  14.     LeaveCriticalSection(FConnectionManager.GetCriticalSection^);
  15.   end;
  16.   ConnectionManager.SetAllowFailover(FQuery, True);
  17. end;

  18. procedure TSimpleQuery.Rollback;
  19. begin
  20.   if ((FQuery.Connection = nil) or not FQuery.Connection.Connected or
  21.     FQuery.Connection.AutoCommit) then exit;
  22.   EnterCriticalSection(FConnectionManager.GetCriticalSection^);
  23.   try
  24.     try
  25.       FQuery.Connection.Rollback;
  26.     except
  27.       LogExceptionMessage;
  28.       raise;
  29.     end;
  30.   finally
  31.     LeaveCriticalSection(FConnectionManager.GetCriticalSection^);
  32.   end;
  33.   ConnectionManager.SetAllowFailover(FQuery, True);
  34. end;

After succeeded creating reusable database connection object accross multiple threads then I create wrapper component for the database connection, transaction dan query object like this:
  1.   ISimpleQuery = interface
  2.     ['{1C1949E4-C472-45BA-8638-5A14545592F8}']
  3.     function GetConnection: TZConnection;
  4.     function GetConnectionManager: IConnectionManager;
  5.     function GetParentQuery: ISimpleQuery;
  6.     function GetQueryObject: TZReadOnlyQuery;
  7.     function GetPrepared: Boolean;
  8.     function GetRecordCount: Integer;
  9.     function GetRowsAffected: Integer;
  10.     function GetActive: Boolean;
  11.     procedure SetActive(AValue: Boolean);
  12.     function GetName: String;
  13.     procedure SetName(const AValue: String);
  14.     function GetFieldDefs: TFieldDefs;
  15.     function GetFields: TFields;
  16.     function GetSQL: TStrings;
  17.     function GetBOF: Boolean;
  18.     function GetEOF: Boolean;
  19.     function GetParams: TParams;
  20.     function GetParamCheck: Boolean;
  21.     procedure SetParamCheck(Value: Boolean);
  22.     function GetConnected: Boolean;
  23.     function GetAutoCommit: Boolean;
  24.     procedure SetAutoCommit(const Value: Boolean);
  25.     function GetRecordAccess: TRecordAccess;
  26.     function GetPost: ITransportVar;
  27.     function GetWhere: ITransportVar;

  28.     procedure Open;
  29.     procedure OpenQuery(const ASQL: String);
  30.     procedure ExecSQL;
  31.     procedure ExecuteQuery(const ASQL: String);
  32.     procedure Close;
  33.     procedure First;
  34.     procedure Next;
  35.     procedure Prior;
  36.     procedure Last;
  37.     procedure Commit;
  38.     procedure Rollback;
  39.     procedure Prepare;
  40.     procedure Unprepare;
  41.     function CreateQuery: ISimpleQuery;
  42.     function FieldByName(const AFieldName: String): TField;
  43.     function FindField(const AFieldName: String): TField;
  44.     function ParamByName(const AParamName: String): TParam;
  45.     procedure Select(const SelectedCols: String);
  46.     procedure Group(const GroupBy: String);
  47.     procedure Order(const OrderBy: String);
  48.     procedure Get(const Table: String);
  49.     procedure Insert(const Table: String);
  50.     procedure Update(const Table: String);
  51.     procedure Delete(const Table: String);
  52.     function GetSQLWhere(AWhere: ITransportVar): String;
  53.     procedure AllowPost(const Columns: String);

  54.     property ConnectionManager: IConnectionManager read GetConnectionManager;
  55.     property ParentQuery: ISimpleQuery read GetParentQuery;
  56.     property Active: Boolean read GetActive write SetActive;
  57.     property Connection: TZConnection read GetConnection;
  58.     property QueryObject: TZReadOnlyQuery read GetQueryObject;
  59.     property FieldDefs: TFieldDefs read GetFieldDefs;
  60.     property Fields: TFields read GetFields;
  61.     property QueryFields[const AFieldName: String]: TField read FieldByName; default;
  62.     property SQL: TStrings read GetSQL;
  63.     property BOF: Boolean read GetBOF;
  64.     property EOF: Boolean read GetEOF;
  65.     property RowsAffected: Integer read GetRowsAffected;
  66.     property RecordCount: Integer read GetRecordCount;
  67.     property Prepared: Boolean read GetPrepared;
  68.     property Params: TParams read GetParams;
  69.     property ParamCheck: Boolean read GetParamCheck write SetParamCheck;
  70.     property Connected: Boolean read GetConnected;
  71.     property AutoCommit: Boolean read GetAutoCommit write SetAutoCommit;
  72.     property Name: String read GetName write SetName;
  73.     property RecordAccess: TRecordAccess read GetRecordAccess;
  74.     property Post: ITransportVar read GetPost;
  75.     property Where: ITransportVar read GetWhere;
  76.   end;

I'm using reference counter in the Interface type to make coding faster by creating query interface object and after the interface object is unused then it's automatically freed and the database connection object, transaction object, the wrapped query object is deallocated and waiting for next use.

I develop two version one with ZeosDBO component and another one with SQLDb component  and both working and very stable.

After I upgraded my application with this database connection pool the client request handling is faster than before.

I'm sorry about my bad english this is the first time i write article in english because maybe alot programmer outside of my country require this knowledge.

Rabu, 30 Agustus 2023

Alasan menggunakan Lazarus dan Delphi di zaman sekarang

Zaman sekarang development tools yang bagus dan sangat maju dan sedang berkembang pesat banyak seperti Java, Java Script, PHP, C#, Go, Dart, Kotlin, C++, Python dan masih banyak lainnya. Diantara banyaknya development tools yang ada dalam keseharian saya masih sering menggunakan aplikasi Lazarus dan Delphi untuk mendevelop aplikasi. Lazarus sendiri merupakan IDE (Integrated Development and Environment) yang memanfaatkan compiler Free Pascal.

Beberapa alasan saya untuk menggunakan Lazarus dan Delphi antara lain sebagai berikut:

  1. Karena sudah sangat nyaman karena terbiasa jadi begitu ada kebutuhan untuk mendevelop aplikasi pakenya ya itu-itu saja.
  2. Menggunakan resource processor dan memori yang kecil sehingga orang-orang seperti saya yang tidak memiliki hardware komputer highend terbaru dengan processor terbaru dan ram yang besar tetap bisa menjalankan aplikasi ini. Zaman saya kuliah dulu cuma menggunakan komputer AMD Sempron 2,1 GHz dengan RAM 1 GB saja masih bisa menjalankan program Delphi 2007 dengan lancar jaya.
  3. Menghasilkan file executable native code dengan optimalisasi yang bagus sehingga bisa berjalan dengan cepat dengan hardware seadanya. Khusus untuk Lazarus dan Delphi yang baru sudah mendukung prosesor 64-bit dengan optimal, sedangkan Delphi 2010 ke bawah masih terbatas pada processor 32-bit.
  4. File executable yang dihasilkan tidak bergantung pada file library yang lain sehingga cukup mendistribusikan satu file executable saja, kecuali memang menggunakan library khusus misal untuk modulasi program atau driver untuk koneksi ke database sehingga memerlukan file library lain tapi terbatas pada library yang dibutuhkan saja. Karena cukup mendistribusikan satu file executable saja sehingga mempermudah deployment dan meminimalkan penggunaan space hard disk maupun ram.
  5. Mungkin karena masih turunan Delphi 1.0 yang dulunya didesain untuk Windows 3.1 yang masih mendukung komputer dengan RAM sekecil 4 MB sehingga standar library bawaan Lazarus dan Delphi didesain agar sangat efisien dalam menggunakan RAM.
  6. Sangat mudah untuk membuat daemon atau windows service sehingga cocok untuk membuat sebuah aplikasi server kecil-kecilan.
  7. Bisa mengakses hardware yang bisa digunakan misalnya untuk membuat SMS Gateway dengan modem GSM.
  8. Khusus untuk Free Pascal, Lazarus dan Delphi terbaru bisa untuk mendevelop multiplatform misal bisa jalan di Windows dan Linux sehingga sangat membantu sekali misalnya ketika harus mendevelop aplikasi server yang dijalankan di VPS Linux yang lebih murah. 

Bagaimanapun juga sebagai development tool tetaplah hanya sebuah tool saja yang membutuhkan programmer untuk memanfaatkannya sehingga menghasilkan produk yang bagus dan bermanfaat. Saya percaya sebuah tool yang bisa memberikan manfaat bagi penggunanya tidak akan pernah punah dan menghilang.

Sekian artikel ini semoga bermanfaat.

Minggu, 26 Juli 2009

Lazarus, sebuah IDE Open Source yang menyerupai Delphi

Lazarus adalah sebuah visual IDE (Integrated Development Environment) yang cross platform dan menyerupai Delphi untuk para developer Pascal dan Object Pascal. Lazarus dibangun untuk dan didukung oleh Free Pascal Compiler. Mulai Maret 2008 Lazarus telah tersedia untuk beberapa distro Linux, Free BSD, Microsoft Windows dan Mac OS X.

Lazarus adalah software gratis seperti Free Pascal. Didistribusikan dengan GNU Lesser General Public License yang diubah. Perubahan memungkinkan lazarus untuk digunakan pada software prorietary.

Free Pascal adalah sebuah kompiler yang berjalan pada banyak sistem operasi. Didesain untuk mengkompilasi source code dalam bahasa Object Pascal sebuah penambahan dari bahasa pemrograman Pascal.

Berbeda dengan Java yang dirancang supaya write once, run anywhere, Lazarus dan Free Pascal dirancang supaya write once, compile everywhere. Karena kompiler yang sama tersedia untuk semua sistem operasi di atas sehingga tidak dibutuhkan coding ulang untuk menghasilkan produk untuk platform-platform yang berbeda, kecuali jika menggunakan fitur yang tergantung pada sistem operasi tertentu. Cross-compiling juga didukung.

Lazarus mulai versi 0.9.26.2 sudah sangat stabil dan bisa dibandingkan dengan Delphi 7.

Kelebihan Lazarus jika dibandingkan dengan Delphi adalah sebagai berikut:

  1. Open Source dan Gratis
  2. Multiplatform, mendukung Windows, Linux, Mac OS dan Pocket PC
  3. Bisa menghasilkan code 64-bit
  4. Dikembangkan oleh komunitas open source sehingga berkembang dengan sangat pesat

Kekurangan Lazarus jika dibandingkan dengan Delphi:

  1. Kurang stabil (versi 0.9.26 ke atas sudah sangat stabil).
  2. Untuk memasang komponen harus mengkompilasi ulang IDE.
  3. Dukungan komponen fihak ke-tiga yang dibuat perusahaan komersial yang berkualitas dan layak digunakan untuk produksi masih kurang, misal: belum tersedianya komponen2 SUIPack, TMS Advanced String Grid, Fast Report, dsb.
  4. Dukungan untuk sistem operasi Windows masih kalah, misalnya: belum bisa mengimpor COM dan ActiveX.
  5. Tidak bisa meletakkan kelas di dalam library.

Lazarus ke depan sangat berpotensi untuk digunakan dalam pembuatan software aplikasi yang cross-platform dan berkualitas. Bahkan saat ini sudah mulai banyak software aplikasi yang dibangun dengan Lazarus, untuk lebih jelasnya silahkan buka http://en.wikipedia.org/wiki/Lazarus_(software) atau investigasi langsung ke situs resmi Lazarus http://lazarus.freepascal.org.

Creating Linux Daemon or Windows Service with Lazarus

Daemon Application in Linux or Service Application in Windows is an application that running in the background, usually automatically starte...