https://github.com/antoniojmsjr/multithreadingfiredac
⚡ Exemplo de utilização de consulta a banco de dados em ambientes multithreading e pool de conexões com FireDAC.
https://github.com/antoniojmsjr/multithreadingfiredac
api-rest delphi fdmanager firedac multithreading pool thread
Last synced: 5 months ago
JSON representation
⚡ Exemplo de utilização de consulta a banco de dados em ambientes multithreading e pool de conexões com FireDAC.
- Host: GitHub
- URL: https://github.com/antoniojmsjr/multithreadingfiredac
- Owner: antoniojmsjr
- License: apache-2.0
- Created: 2022-02-25T21:51:13.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2024-09-15T17:58:17.000Z (almost 2 years ago)
- Last Synced: 2025-06-20T00:08:53.353Z (about 1 year ago)
- Topics: api-rest, delphi, fdmanager, firedac, multithreading, pool, thread
- Homepage:
- Size: 5.08 MB
- Stars: 56
- Watchers: 3
- Forks: 12
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Multithreading (FireDAC)
Em uma aplicação multithread, uma boa prática é isolar os componentes de acesso ao banco de dados, a violação dessa prática pode gerar *erros* do tipo access violation entre outros erros. Para ajudar a resolver esse problema, a [Embarcadero](https://www.embarcadero.com/br/) disponibilizou o componente, **[FDManager](http://docwiki.embarcadero.com/Libraries/Rio/en/FireDAC.Comp.Client.TFDManager)**, que é responsável pela *definição* e *gerenciamento* das conexões e é **thread-safe**(utilização segura em ambientes multithread).
**Fonte:** https://docwiki.embarcadero.com/RADStudio/Sydney/en/Multithreading_(FireDAC)
**Vantagens do uso do FDManager**
* Definição da biblioteca cliente de acesso ao banco de dados. [OPCIONAL]
* Por exemplo:
* Definição do local da biblioteca cliente(fbclient.dll) do Firebird 2.5;
* Definição do local da biblioteca cliente do Firebird(fbclient.dll) 64Bits;
* Centralização das configurações de conexão com o banco de dados.
* Por exemplo:
* Definição das configurações de acesso ao banco de dados de produção.
* Definição das configurações de acesso ao banco de dados de log.
* Centralização das parametrizações do componente TFDConnection. (Esta configuração se estende para todos os FDConnection usado na aplicação)
* Por exemplo:
* FetchOptions.Mode := TFDFetchMode.fmAll;
* ResourceOptions.AutoConnect := True;
Além do uso do **FDManger** uma boa prática e o uso da técnica de otimização de conexão com o banco de dados, chamado de **pool de conexões**.
### O que é pool de conexões com Banco de Dados?
Quando precisamos realizar qualquer operação sobre um banco de dados é primeiramente necessário estabelecer uma conexão com ele, o estabelecimento dessa conexão costuma ocorrer através do protocolo **TCP/IP**, envolvendo custo de **abertura** e **fechamento** da conexão. Esse custo é particularmente significativo em *aplicações Web* onde você pode ter um fluxo de milhares de requisições constante, e cada uma delas vai gerar a abertura e fechamento da conexão com o banco de dados. Uma técnica simples para evitar esse constante "abre-fecha" de conexões é manter um determinado número de conexões sempre aberta (um **pool** de conexões) e simplesmente reutilizar quando necessário, dessa forma você diminui tanto o gasto de recurso da máquina quanto o tempo de resposta da sua aplicação.
Esse custo para estabelecer uma conexão com o banco de dados pode ser visto na imagem abaixo, utilizando a ferramenta *WireShark* podemos ver a quantidade de pacotes que é utlizado para executar um simples select.

Podemos ver na imagem abaixo o comportamento das consultas ao banco de dados usando pool de conexões:
* Do lado esquerdo o famoso "abre-fecha", um exemplo de consulta sem a utilização do pool de conexões.
* Do lado direito, um exemplo de consulta utilizando pool de conexões.

### Configuração do pool de conexões
Para configurar um pool de conexões utilizaremos o **FDManager**, e as propriedades de pool.
| Parâmetro | Descrição | Exemplo |
|---|---|---|
|Pooled|Ativa o pool de conexões para um ConnectionDefName informado em FDManager.ConnectionDefs. Para usar um pool de conexões, a definição de conexão deve ser [persistente](https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Defining_Connection_(FireDAC)#Creating_a_Persistent_Connection_Definition) ou [privada](https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Defining_Connection_(FireDAC)#Creating_a_Private_Connection_Definition).|True|
|POOL_CleanupTimeout|O tempo em milissegundos até o FireDAC **remover** as conexões que não foram usadas até o tempo POOL_ExpireTimeout.O valor padrão é 30000 ms (30 segundos).|15000 ms15 s |
|POOL_ExpireTimeout|O tempo em milissegundos, após o qual a **conexão inativa** pode ser excluída do pool e destruída.O valor padrão é 90000 ms (90 segundos).|60000 ms60 s |
|POOL_MaximumItems|O número máximo de conexões no Pool.Quando o aplicativo requer mais conexões, uma exceção é gerada. O valor padrão é 50.**Quando se atinge o número total de conexões especificada nessa propriedade, é gerado uma exceção:**|100|
Em geral, o **FDManager** mantém um pool de conexões "física" aberta, quando:
* Quando TFDConnection.Connected é definido como **True**, o FireDAC pega uma conexão "física" do pool e a usa.
* Quando TFDConnection.Connected é definido como **False**, a conexão "física" não é fechada, mas colocada de volta no pool.
### Configuração de acesso ao banco de dados
Para usar o **FDManager** com outros bancos de dados, verificar o link: [Database Connectivity (FireDAC) #Driver Linkage](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Database_Connectivity_(FireDAC))
| Database | DriverID | TFDConnectionDefParams | Units |
|---|---|---|---|
| [Microsoft SQL Server](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_Microsoft_SQL_Server_(FireDAC)) | MSSQL | TFDPhysMSSQLConnectionDefParams | FireDAC.Phys.MSSQLDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.ODBCBase, FireDAC.Phys.MSSQL |
| [Oracle Server](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_Oracle_Server_(FireDAC)) | Ora | TFDPhysOracleConnectionDefParams | FireDAC.Phys.OracleDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.Oracle |
| [PostgreSQL](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_PostgreSQL_(FireDAC)) | PG |TFDPhysPGConnectionDefParams | FireDAC.Phys.PGDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.PG; |
| [MySQL Server](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_MySQL_Server_(FireDAC)) | MySQL | TFDPhysMySQLConnectionDefParams | FireDAC.Phys.MySQLDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.MySQL |
| [IBM DB2 Server](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_IBM_DB2_Server_(FireDAC))) | DB2 | TFDPhysDB2ConnectionDefParams | FireDAC.Phys.DB2Def, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.ODBCBase, FireDAC.Phys.DB2 |
| [Firebird](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_Firebird_(FireDAC)) | FB | TFDPhysFBConnectionDefParams | FireDAC.Phys.FBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.IBBase, FireDAC.Phys.FB |
| [InterBase](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_InterBase_(FireDAC)) | IB | TFDPhysIBConnectionDefParams | FireDAC.Phys.IBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.IBBase, FireDAC.Phys.IB |
| [SQLite](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_SQLite_database_(FireDAC)) | SQLite | TFDPhysSQLiteConnectionDefParams | FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.SQLite |
| [MongoDB](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_MongoDB_Database_(FireDAC)) | Mongo | TFDPhysMongoConnectionDefParams | FireDAC.Phys.MongoDBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.MongoDB |
| [ODBC](https://docwiki.embarcadero.com/RADStudio/Sydney/en/Connect_to_ODBC_Data_Source_(FireDAC)) | ODBC | TFDPhysODBCConnectionDefParams | FireDAC.Phys.ODBCDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.ODBCBase, FireDAC.Phys.ODBC |
* FireDAC databases supported by RAD Studio: [FireDAC Database Support](https://docwiki.embarcadero.com/Status/en/FireDAC_Database_Support)
## Exemplos
Em anexo no projeto existem dois exemplos de uso de conexão com o banco de dados em ambientes multithread.
1º Exemplo, usando conexões em ambiente multithreading para *desktop*.
* Exemplo compilado: [Download](https://github.com/antoniojmsjr/MultithreadingFireDAC/files/14411938/MultithreadingFireDAC.zip)
2º Exemplo, usando conexões em ambiente multithreading para servidor web com [Horse](https://github.com/HashLoad/horse).
* Dependência middlewares
* [Jhonson](https://github.com/HashLoad/jhonson)
* [Handle-exception](https://github.com/HashLoad/handle-exception)
* Teste de stress com [JMeter](https://jmeter.apache.org/)
Ambos os exemplo usam o banco de dados Firebird
* [Firebird 2.5](https://firebirdsql.org/en/firebird-2-5/)
* Banco MultithreadingFireDAC.FDB
* Tabela MULTITHREADING com 100.000 mil registros.
### Exemplo de consulta com pool de conexões ATIVADO:
* Tempo de execução: 00:00:16.193
https://github.com/antoniojmsjr/MultithreadingFireDAC/assets/20980984/94dea460-6932-4c9b-89a9-0db6ff67b4c7
### Exemplo de consulta com pool de conexões DESATIVADO:
* Tempo de execução: 00:01:00.929
https://github.com/antoniojmsjr/MultithreadingFireDAC/assets/20980984/75e72a62-5c7d-44c1-86e9-ed0e47cbcac8