Pool de conexiones en PHP
Rodrigo Fuentealba
darkprox en gmail.com
Vie Feb 10 15:08:59 CLST 2006
JuanPa wrote:
> Hola listeros....
> Te agradezco nuevamente Rodrigo por dar tu valioso tiempo aclarando
> mis dudas,
>
> A raiz de es comentario es que he optado por utilizar mis clasicas
> conexiones no persistentes .
ejalé ;)
>
> Es mejor usar conexiones no persistentes, es decir, abriendo la
> conexión
> al principio de tu script y cerrando la conexión al final, pues
> siempre
> vas a tener páginas que no hagan ninguna consulta a la base de
> datos...
> ¿Para qué, entonces, tendrás una conexión abierta? Es únicamente un
> desperdicio de recursos.
>
>
> Ademas no voy a esperar que el GC (Garbage Colector) haga su trabajo,
> una ultima cosa...
Bueno el recolector de basura funcionará igual, pero cerrando menos cosas.
>
> Por eso es mejor abrir la conexión al principio de un script y
> cerrarla
> al final, y si tienes funciones que recuperan datos como el caso
> de tu
> buscar alumno, en vez de abrir una conexión nueva, preguntes si ya hay
> una conexión abierta para aprovecharla.
>
>
> Pero ¿ esto no significa que la conexion deberìa ser persistente? o te
> refieres a que deberia pasar por parametros a mi objeto conexion que
> tiene un recurso de conexion interno($link) y luego verificar si esta
> está abierta.
Una conexión no persistente se abre al inicio de un archivo (supongamos
insertar.php) y se debe cerrar al final de éste. Si tienes un archivo
que se llama modificar.php, ese debe declarar otra conexión, pues la
primera no estará.
La conexión persistente se abre al inicio de la sesión (mientras el
usuario está conectado) y puede pasarse por varias páginas. Si tienes un
archivo insertar, modificar, eliminar, buscar, etc, cuantoquieras.php,
todos esos archivos usarán conexiones persistentes.
<!-- leo de otro mail
una conexion persistente permite re-utilizar una conexion ya abierta,
ademas de tener que cerrarla explicitamente sino queda "abierta"! la
idea es evitar el tiempo (milisegundos?) que se ocupa en "establecer"
una conexion. su uso a mi entender esta reservado a sitios con muchas
conexiones nuevas, con procesos cortos.
-- leido -->
Esto es cierto, yo dije "una vez por usuario/sesión", queriendo enfocar
a que la conexión estaba abierta y podía ser aprovechada por varias
páginas que visita un usuario desde un navegador. (pues una conexión se
abre solamente para un usuario).
> Y finalmente cuando dices...
>
> Cualquiera de las dos conexiones funciona así, la diferencia es
> que la
> persistente la abres una vez por usuario (o por conexion?) ...
>
> Esto significa ¿ Que la conexion seguira abierta en cada script que
> valla ejecutando el usuario, mientras no se cierre explicitamente en
> otro script o cuando el usuario cierre el navegador ?
Ahhh, eso con ejemplo (ahora haré código real con adodb)... "notese,
solamente una conexión no persistente"
<?php
echo("Abriendo la primera conexión")
$conexion = ADONewConnection("postgres");
$conexion->NConnect($host,$user,$pass,$base);
$sql = $conexion->Prepare("SELECT * FROM alumno WHERE rut_alumno = ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
$conexion->Close();
echo("Abriendo la segunda conexión");
$conexion = ADONewConnection("postgres");
$conexion->NConnect($host,$user,$pass,$base);
$sql = $conexion->Prepare("SELECT * FROM apoderado WHERE rut_alumno
= ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
$conexion->Close();
$conexion = ADONewConnection("postgres");
$conexion->NConnect($host,$user,$pass,$base);
$sql = $conexion->Prepare("SELECT * FROM cuotas WHERE rut_alumno = ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
$conexion->Close();
?>
El ejemplo anterior es un script demasiado mega mal hecho. Abres tres
veces una conexión nueva y no destruyes las conexiones anteriores.
Digamos que solamente las desconectas. Uhhh, en este pequeño script te
gastaste tres conexiones. ¿Qué mal, no?. Pues ahora veamos cómo lo
habría hecho con una sola conexión no persistente.
<?php
echo("Abriendo la conexión")
$conexion = ADONewConnection("postgres");
$conexion->NConnect($host,$user,$pass,$base);
dibujemos();
// con la misma conexion no persistente, puedes hacer UNA
$sql = $conexion->Prepare("SELECT * FROM alumno WHERE rut_alumno = ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
juguemos_en_el_bosque();
// DOS
$sql = $conexion->Prepare("SELECT * FROM apoderado WHERE rut_alumno
= ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
mientras_el_lobo_no_esta();
// TRES y más consultas en el mismo script.
$sql = $conexion->Prepare("SELECT * FROM cuotas WHERE rut_alumno = ?");
$rs = $conexion->Execute($sql,array('12345678-9'));
lobo_esta(?);
// Y antes de cerrar el script, la conexión se cierra sola.
$conexion->Close();
terminado();
exit();
?>
El ejemplito este aprovecha una sola conexión no persistente, pero
usando solamente "UN" script, lo cual a pesar de que está bien, te
ensucia un poco el código y te lo hace un poquito ilegible, por todas
esas SQL por aquí y por allá. OK, ahora vamos a hacer un script para las
funciones, un script para abrir y cerrar la conexión, y tu script de
lógica de negocios:
<!-- conexion.php -->
<?php
// nuestra función que nos abre muchas puertas
function abrir_conexion()
{
require_once('adodb/adodb.inc.php');
$host = "123.123.123.123";
$user = "postgres";
$pass = "nula";
$base = "carepescao";
$conexion = ADONewConnection("postgres");
$conexion->NConnect($host, $user, $pass, $base);
if(!$conexion->IsConnected)
{
die("Arghhh mi jefe me va a matar! me pitié la conexión");
}
}
// la función que cierra con llave cuando nos vayamos ;)
function cerrar_conexion();
{
if($conexion->IsConnected)
{
$conexion->Close();
}
}
?>
<!-- leo nuevamente:
originalmente tu preguntaste por un "pool" de conexiones lo cual es
diferente ya que ahi se puede compartir conexiones *entre* procesos, y
eso en PHP se tiene que hacer con ayuda externa.
-->
Nótese que compartir conexiones entre procesos (pooling) tiene
diferencias con aprovechar las conexiones no persistentes: lo que vamos
a hacer en el siguiente archivo aprovecha una conexión no persistente
que esté abierta, en vez de estar abriendo y cerrando. Esto para mí
también es llamado pooling, pero básico, y aunque no sea un proceso
automatizado, así es como trabaja... La idea es siempre tener una y sólo
una conexión disponible cuando la usemos sin tener que abrirla más que
lo necesario, y cerrarla cuando ya tengamos todas nuestras operaciones
hechas y no vayamos a usarla de inmediato, bien por estar requiriendo
datos, bien por ya haberlos obtenido y estamos mostrándolos en otra
página. La cerramos para liberar recursos y así optimizamos cualquier
cantidad de memoria. Esta clase de pooling no comparte conexiones entre
procesos (para mí un proceso tiene un PID y tiene un destino distinto).
<!-- sql.php -->
<?php
require_once 'conexion.php';
// una funcion que lo unico que hace es retornar el recordset.
function buscar_alumno($rut)
{
if(!$conexion->IsConnected || !isset($conexion))
{
abrir_conexion();
}
$sql = $conexion->Prepare("SELECT * FROM alumno WHERE rut_alumno
= ?");
$rs = $conexion->Execute($sql,array($rut));
return $rs;
}
// una funcion que lo unico que hace es retornar el recordset.
function buscar_apoderado($rut)
{
if(!$conexion->IsConnected || !isset($conexion))
{
abrir_conexion();
}
$sql = $conexion->Prepare("SELECT * FROM apoderado WHERE
rut_alumno = ?");
$rs = $conexion->Execute($sql,array($rut));
return $rs;
}
// una funcion que lo unico que hace es retornar el recordset.
function buscar_cuotas($rut)
{
si la conexión no existe, o no se ha seteado, entonces abrimos
la conexion. Si la conexion existe, para que?
if(!$conexion->IsConnected || !isset($conexion))
{
abrir_conexion();
}
$sql = $conexion->Prepare("SELECT * FROM cuotas WHERE rut_alumno
= ?");
$rs = $conexion->Execute($sql,array($rut));
return $rs;
}
?>
<!-- bussiness.php -->
<?php
require_once 'conexion.php';
require_once 'sql.php';
// abrimos la conexion();
abrir_conexion();
// procesamos algunas cosas...
dibujemos();
// llamamos a nuestra consulta.
// esto ya es lógica de negocios, ¿no?
$resultado1 = buscar_alumno($rut);
// tururururu, me gusta cantar...
juguemos_en_el_bosque();
// nuestra logica de negocios requiere que
// busquemos al responsable por el cabro de ... ;)
$resultado2 = buscar_apoderado($rut);
// el lobo andaba comiéndose unas abuelitas por ahi
mientras_el_lobo_no_esta();
// de nuevo, no necesitamos de SQL feos por ahi...
$resultado3 = buscar_cuotas($rut);
// mostramos los resultados en la pantalla...
lobo_esta(?);
// cerramos la conexion...
cerrar_conexion();
// cerramos algunas otras cosillas, o bien cargamos el footer, que
se yo,
terminado();
// una vieja costumbre mía, heredada de los antiguos BASIC de ATARI.
// nadie me ha convencido de que esto no es necesario
exit();
?>
Como puedes ver, finalmente son más archivos, pero el que te interesa
que es la lógica de negocios, te queda lindo para leer. La cosa es
diseñar un poco más ordenado. El que programes en 3, 4, 5 o 100 capas si
quieres no significa que las capas no se interconecten, pues la lógica
de presentación necesita que la lógica de negocios le pase datos, y la
lógica de negocios necesita conectarse a la base de datos, para que
tenga algo que procesar!!!
> Mil disculpas si soy muy pregunton, pero siempre me gusta sacar
> conclusiones valiosas de las conversaciones.... Gracias de antemano...
Cero dramas. Si Google no es claro en el asunto (de hecho no lo fue
cuando lo investigué) no hay problemas en discutirlo y aclarar las dudas.
> Nos leemos
> -----------------
> Juan Pablo
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: http://listas.inf.utfsm.cl/pipermail/php/attachments/20060210/d1b99158/attachment-0001.html
Más información sobre la lista de distribución PHP