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 disponibilizou o componente, FDManager, 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;
- Por exemplo:
-
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.
- Por exemplo:
-
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;
- Por exemplo:
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.
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.
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 ou privada. |
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 ms 15 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 ms 60 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.
Para usar o FDManager com outros bancos de dados, verificar o link: Database Connectivity (FireDAC) #Driver Linkage
Database | DriverID | TFDConnectionDefParams | Units |
---|---|---|---|
Microsoft SQL Server | MSSQL | TFDPhysMSSQLConnectionDefParams | FireDAC.Phys.MSSQLDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.ODBCBase, FireDAC.Phys.MSSQL |
Oracle Server | Ora | TFDPhysOracleConnectionDefParams | FireDAC.Phys.OracleDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.Oracle |
PostgreSQL | PG | TFDPhysPGConnectionDefParams | FireDAC.Phys.PGDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.PG; |
MySQL Server | MySQL | TFDPhysMySQLConnectionDefParams | FireDAC.Phys.MySQLDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.MySQL |
IBM DB2 Server) | DB2 | TFDPhysDB2ConnectionDefParams | FireDAC.Phys.DB2Def, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.ODBCBase, FireDAC.Phys.DB2 |
Firebird | FB | TFDPhysFBConnectionDefParams | FireDAC.Phys.FBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.IBBase, FireDAC.Phys.FB |
InterBase | IB | TFDPhysIBConnectionDefParams | FireDAC.Phys.IBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.IBBase, FireDAC.Phys.IB |
SQLite | SQLite | TFDPhysSQLiteConnectionDefParams | FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.SQLite |
MongoDB | Mongo | TFDPhysMongoConnectionDefParams | FireDAC.Phys.MongoDBDef, FireDAC.Stan.Intf, FireDAC.Phys, FireDAC.Phys.MongoDB |
ODBC | 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
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
2º Exemplo, usando conexões em ambiente multithreading para servidor web com Horse.
- Dependência middlewares
- Teste de stress com JMeter
Ambos os exemplo usam o banco de dados Firebird
- Firebird 2.5
- Banco MultithreadingFireDAC.FDB
- Tabela MULTITHREADING com 100.000 mil registros.
- Tempo de execução: 00:00:16.193
ConsultaPoolConexoes_Ativado.mp4
- Tempo de execução: 00:01:00.929