Last 5.3 release ever available: PHP 5.3.29 - 5.3 now EOL

Conexão Permanente com o Banco de Dados

Conexões persistentes são conexões que não fecham quando a execução do seu script termina. Quando uma conexão persistente é requisitada, o PHP checa se já existe uma conexão persistente idêntica (que foi mantida aberta anteriormente) - e, se ela existe, ele a usa. Se não existir, ele cria uma nova. Uma conexão 'idêntica' é uma conexão que foi aberta ao mesmo host, com o mesmo nome de usuário e a mesma senha (onde for aplicável).

Pessoas que não estão totalmente familiarizadas com a maneira como servidores web trabalham e distribuem a carga podem confundir conexões persistentes com o que elas não são. In particular, elas não dão a você a habilidade de abrir 'sessões de usuários' na mesma conexão, elas não dão a habilidade de construir uma transação eficientemente, e elas não fazem um monte de outras coisas. De fato, para ser extremamente claro sobre o assunto, conexões persistentes não te dão nenhuma funcionalidade que não era possível com as suas correspondentes não-persistentes.

Por que?

Tem a ver com a maneira como os servidores web funcionam. Existem três maneiras de seu servidor web utilizar o PHP para gerar páginas.

O primeiro método é usar o PHP como um CGI "wrapper". Quando executado dessa maneira, uma instância do interpretador do PHP é criada e destruída para cada requisição de página (por uma página PHP) para o seu servidor web. Como ela é destruída após cada requisição, quaisquer recursos que ela adquirir (como uma conexão para um banco de dados) são fechados quando ela é destruída. Nesse caso, não há nenhum ganho ao tentar usar conexões persistentes -- elas simplesmente não persistem.

O segundo método, o mais popular, é rodar o PHP como um módulo em um servidor com multi-processos, que atualmente só inclue o Apache. Um servidor com multi-processos tipicamente tem um processo (pai) que coordena uma série de processos (filhos) que são os que realmente fazem o trabalho de servir as páginas. Quando uma requisição chega de um cliente, ela é entregue à um dos filhos que não estiver ocupado servindo outro cliente. Isso significa que quando o mesmo cliente faz uma segunda requisição ao servidor, ele pode ser servido por um processo filho diferente do da primeira vez. Quando abre-se uma conexão persistente, cada página que requisitar serviços de SQL pode reusar a mesma conexão estabelecida ao servidor SQL.

O último método é usar o PHP como um plug-in para um servidor web multithreaded. Atualmente, o PHP4 tem suporte para ISAPI, WSAPI, e NSAPI (no Windows), todos permitindo PHP ser usado como um plug-in em servidores multithreaded como Netscape FastTrack (iPlanet), Internet Information Server (IIS) da Microsoft, e O'Reilly's WebSite Pro. O comportamento é essencialmente o mesmo do modelo multiprocessado descrito anteriormente.

Se conexões persistentes não tem nenhuma funcionalidade a mais, para que elas servem?

A resposta é extremamente simples -- eficiência. Conexôes persistentes são boas se o sobrecarga (overhead) de criar uma conexão ao seu servidor SQL for alta. Saber se essa sobrecarga é alta depende de vários fatores. Como que tipo de banco de dados é, se está ou não na mesma máquina onde o servidor web está, o quão carregada de trabalho está a máquina hospedando o servidor SQL e assim por diante. O ponto é que se a sobrecarga de conexão for alta, conexões persistentes ajudam consideravelmente. Elas fazem com que os processos filhos simplesmente conectam-se uma vez só durante toda sua duração, ao invés de cada vez que eles processam uma página que requer uma conexão ao servidor SQL. Isso significa que cada filho que abriu uma conexão persistente terá sua própria conexão aberta ao servidor. Por exemplo, se você tiver 20 processos filhos diferentes que rodassem um script que fizesse uma conexão persistente à um servidor SQL, você teria 20 conexões diferentes ao banco, uma de cada filho.

Perceba, no entanto, que isso pode ter algumas desvantagens se você estiver usando um banco com limite de conexões que é excedido pela conexões persistentes filhas. Se seu banco tem um limite de 16 conexões simultâneas, e durante um momento de pico de acessos, 17 processos filhos tentam fazer a conexão, um deles não será capaz. Se houver bugs no seus scripts que não permitem que as conexões se fechem (como loops infinitos) o banco de dados com apenas 16 conexões pode rapidamente ficar sobrecarregado. Procure na documentação do seu banco por informações sobre como lidar com conexões ociosas ou abandonadas.

Aviso

Existem mais alguns cuidados a se tomar quando usando conexões persistentes. Um deles é que, quando usando travamento de tabela em uma conexão persistente, se o script por qualquer razão não pode destravar a mesma, então scripts subsequentes usando a mesma conexão serão bloqueados indefinidamente e pode ser preciso reiniciar o servidor http ou o banco de dados. Outro cuidado a se ter é, quando usando transações, um bloco de transação também será carregado para o próximo script que usar a conexão se a execução do script terminar primeiro que o bloco de transação. Em ambos os casos, você pode usar register_shutdown_function() para registrar uma função simples de limpeza para destravar suas tabelas e fazer roll back de suas transação. O ideal é evitar o problema completamente não usando conexões persistentes em scripts que usam travamento de tabelas ou transações (você ainda pode usar elas nos outros casos).

Um resumo importante. Conexões persistente foram feitas para ter um mapeamento de um-para-um com conexões normais. Isso significa que você deve sempre ser capaz de substituir conexões persistentes com conexões não-persistentes e isso não mudará a maneira como seu script se comporta. Pode (e provavelmente irá) mudar a eficiência do mesmo, mas não o seu comportamento!

Veja também fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), ingres_pconnect(), msql_pconnect(), mssql_pconnect(), mysql_pconnect(), ociplogon(), odbc_pconnect(), ora_plogon(), pfsockopen(), pg_pconnect(), e sybase_pconnect().

add a note add a note

User Contributed Notes 12 notes

up
7
christopher dot jones at oracle dot com
7 years ago
For the oci8 extension it is not true that " [...] when using transactions, a transaction block will also carry over to the next script which uses that connection if script execution ends before the transaction block does.".  The oci8 extension does a rollback at the end scripts using persistent connections, thus ending the transaction.  The rollback also releases locks. However any ALTER SESSION command (e.g. changing the date format) on a persistent connection will be retained over to the next script.
up
4
fabio
8 years ago
You can in fact provide a port for the connection, take a look at http://de2.php.net/manual/en/function.mysql-pconnect.php#AEN101879

Just use "hostname:port" for the server address.
up
3
ambrish at php dot net
3 years ago
In IBM_DB2 extension v1.9.0 or later performs a transaction rollback on persistent connections at the end of a request, thus ending the transaction. This prevents the transaction block from carrying over to the next request which uses that connection if script execution ends before the transaction block does.
up
3
RQuadling at GMail dot com
8 years ago
If you have multiple databases on the same server AND you are using persistent connections, you MUST prefix all the table names with the specific database name.

Changing the database using the xxx_select_db functions alters the database for the connection for all users who are sharing that connection (assuming PHP is running shared and not CGI/CLI).

If you have 2 databases (live and archive) and your script is talking to both, you cannot use 2 persistent connections and change the database for each one.

Internally, persistent connections are used even if you do not specify that you want to use persistent connections. This is why new_link was added to mysql_connect/mssql_connect (PHPV4.2.0+).
up
1
Tom
4 years ago
There's a third case for PHP: run on a fastCGI interface. In this case, PHP processes are NOT destroyed after each request, and so persistent connections do persist. Set PHP_FCGI_CHILDREN << mysql's max_connections and you'll be fine.
up
1
whatspaz at g NO dot SPAM mail dot c o m
7 years ago
in response to web at nick, have you tried FLUSH PRIVILEGES. this should reload those privileges.
up
0
php at alfadog dot net
6 months ago
One additional not regarding odbc_pconnect  and possibly other variations of pconnect:

If the connection encounters an error (bad SQL, incorrect request, etc), that error will return with  be present in odbc_errormsg for every subsequent action on that connection, even if subsequent actions don't cause another error.

For example:

A script connects with odbc_pconnect.
The connection is created on it's first use.
The script calls a query "Select * FROM Table1".
Table1 doesn't exist and odbc_errormsg contains that error.

Later(days, perhaps), a different script is called using the same parameters to odbc_pconnect.
The connection already exists, to it is reused.
The script calls a query "Select * FROM Table0".
The query runs fine, but odbc_errormsg still returns the error about Table1 not existing.

I'm not seeing a way to clear that error using odbc_ functions, so keep your eyes open for this gotcha or use odbc_connect instead.
up
0
ynzhang from lakeheadu canada
5 years ago
It seems that using pg_pconnect() will not persist the temporary views/tables. So if you are trying to create temporary views/tables with the query results and then access them with the next script of the same session, you are out of luck. Those temporary view/tables are gone after each PHP script ended. One way to get around this problem is to create real view/table with session ID as part of the name and record the name&creation time in a common table. Have a garbage collection script to drop the view/table who's session is expired.
up
-1
andy at paradigm-reborn dot com
7 years ago
To those using MySQL and finding a lot of leftover sleeping processes, take a look at MySQL's wait_timeout directive. By default it is set to 8 hours, but almost any decent production server will have been lowered to the 60 second range. Even on my testing server, I was having problems with too many connections from leftover persistent connections.
up
-2
jean_christian at myrealbox dot com
12 years ago
If anyone ever wonders why the number of idle db process (open connections) seems to grow even though you are using persistent connections, here's why:

"You are probably using a multi-process web server such as Apache. Since
database connections cannot be shared among different processes a new
one is created if the request happen to come to a different web server
child process."
up
-2
aaryal at foresightint dot com
10 years ago
this one bit quite a bit of chunk out of my you-know-what. seems like if you're running multiple database servers on the same host (for eg. MySQL on a number of ports) you can't use pconnect since the port number isn't part of the key for database connections. especially if you have the same username and password to connect to all the database servers running on different ports. but then it might be php-MySQL specific. you might get a connection for an entirely different port than the one you asked for.
up
-7
jorgeleon85 at gmail dot com
3 years ago
I've been looking everywhere for a benchmark or at least comparison of the overhead used by oci_connect and oci_pconnect.
Just saying "oci_connect is slower because the overhead..." is not enough for me. For than I wrote a couple scripts to compare perfomance.
At the end I found out an average of 34% more time using a oci_connect than oci_pconnect, using a query of 50 rows and 100 columns.
Obviously this wasn't a real benchmark however it gives a simple idea of the efficiency of each function.
To Top