2008-09-19 44 views
28

He desarrollado algunas clases personalizadas tipo DAO para cumplir con algunos requisitos muy especializados para mi proyecto que es un proceso del lado del servidor que no se ejecuta dentro de ningún tipo de marco.¿Cuál es la mejor solución para la agrupación de conexiones de bases de datos en python?

La solución funciona bien, excepto que cada vez que se realiza una nueva solicitud, abro una nueva conexión a través de MySQLdb.connect.

¿Cuál es la mejor solución "drop-in" para pasar esto a usar la agrupación de conexiones en python? Me estoy imaginando algo así como la solución DBCP de commons para Java.

El proceso es de larga duración y tiene muchos hilos que necesitan realizar solicitudes, pero no todos al mismo tiempo ... específicamente, hacen un montón de trabajo antes de breves ráfagas de escribir una parte de sus resultados.

Editado para añadir: Después de un poco más de buscar encontré anitpool.py la que se ve decente, pero como estoy relativamente nuevo a Python que supongo que sólo quiero asegurarme de que no me falta una más obvia/idiomática más/mejor solución.

Respuesta

15

OMI, el "/ idiomática más/mejor solución más evidente" es utilizar un ORM existentes en lugar de inventar clases DAO-like .

Me parece que los ORM son más populares que las conexiones SQL "en bruto". ¿Por qué? Porque Python es OO, y la asignación de la fila SQL al objeto es absolutamente esencial. No hay muchos casos en los que trate con filas SQL que no se asignan a objetos Python.

Creo que SQLAlchemy o SQLObject (y la agrupación de conexiones asociada) la solución Pythonic más idiomática.

La agrupación como una característica separada no es muy común porque el SQL puro (sin asignación de objetos) no es muy popular para el tipo de procesos complejos de larga ejecución que se benefician de la agrupación de conexiones. Sí, SQL puro es usado, pero siempre se usa en aplicaciones más simples o más controladas donde la agrupación no es útil.

que cree que puede tener dos alternativas:

  1. Revisar sus clases para utilizar SQLAlchemy o SQLObject. Si bien esto parece doloroso al principio [todo el trabajo desperdiciado], debería poder aprovechar todo el diseño y el pensamiento, y es simplemente un ejercicio de adopción de una solución ORM y de agrupación ampliamente utilizada.
  2. Despliegue su propio grupo de conexiones simples utilizando el algoritmo que ha descrito: un conjunto simple o una lista de conexiones que recorre.
15

Envuelva su clase de conexión.

Establezca un límite en la cantidad de conexiones que realiza. Devuelve una conexión no utilizada. Interceptar cerca para liberar la conexión.

Actualización: puse algo como esto en dbpool.py:

import sqlalchemy.pool as pool 
import MySQLdb as mysql 
mysql = pool.manage(mysql) 
+2

Chris, seguramente alguien ya ha construido esto? En el peor de los casos, puedo escribirlo yo mismo, pero obviamente este debería ser un requisito bastante común para las personas que no utilizan los ORM/frameworks existentes, y estoy seguro de que alguien más ya ha creado una solución que ha sido probada con el tiempo. – John

+0

He hecho esto antes, con Oracle, y creo que involucraba menos de 50 líneas de código, total. Básicamente, use una identificación, diccionario, almacene la conexión, almacene el estado de uso, etc. ¿Muy simple? – Chris

+3

@Chris, por esa cadena de lógica, también debería comenzar a implementar mis listas y hasmaps por mi cuenta. –

21

En MySQL?

Yo diría que no te molestes con la agrupación de conexiones.A menudo son una fuente de problemas y con MySQL no te ofrecerán la ventaja de rendimiento que estás esperando. Este camino puede ser un gran esfuerzo a seguir, políticamente, porque hay muchas mejores prácticas agitando las manos y verborrea en los libros de texto en este espacio sobre las ventajas de la combinación de conexiones.

Las agrupaciones de conexiones son simplemente un puente entre la era post-web de aplicaciones sin estado (por ejemplo, el protocolo HTTP) y la era pre-web de aplicaciones de procesamiento por lotes de larga duración con estado. Como las conexiones eran muy costosas en las bases de datos anteriores a la web (ya que a nadie solía importarle cuánto tardaba la conexión en establecerse), las aplicaciones post-web idearon este esquema de grupo de conexiones para que cada golpe no incurriera en este gran procesamiento en el RDBMS.

Como MySQL es más un RDBMS de la era web, las conexiones son extremadamente livianas y rápidas. He escrito muchas aplicaciones web de gran volumen que no usan ningún conjunto de conexiones para MySQL.

Esta es una complicación de la que puede beneficiarse prescindiendo, siempre que no haya un obstáculo político que superar.

+10

8 años después de la publicación de esta respuesta y la agrupación continúa siendo relevante. Si ejecuta una aplicación web con mucho tráfico, puede ejecutar fácilmente el límite de "Demasiadas conexiones", independientemente de su apatridia. Un grupo ayudará a mitigar esto al esperar una conexión gratuita en lugar de fallar. Además, si desea escalar horizontalmente su servidor de aplicaciones, es probable que su base de datos no viva en la misma máquina. En este caso, lo más probable es que desee conectarse a través de HTTPS, que tiene una sobrecarga significativa. Un grupo ayudará aquí también. – Joe

3

fabricación de su propia agrupación de conexiones es una mala idea si su aplicación alguna vez decide empezar a utilizar multi-threading. Hacer un grupo de conexión para una aplicación de subprocesos múltiples es mucho más complicado que uno para una aplicación de subproceso único. Puedes usar algo como PySQLPool en ese caso.

También es una MALA idea usar un ORM si está buscando rendimiento.

Si se le trata con grandes bases de datos/pesados ​​que tienen que manejar una gran cantidad de inserciones, selecciona, actualizaciones y borrados al mismo tiempo, entonces usted va a necesitar el rendimiento, lo que significa que tendrá personalizada SQL escrito para optimizar las búsquedas y los tiempos de bloqueo. Con un ORM generalmente no tienes esa flexibilidad.

Así que básicamente, sí, puede hacer su propio grupo de conexiones y usar ORM, pero solo si está seguro de que no necesitará nada de lo que acabo de describir.

5

hilo viejo, pero para la puesta en común de propósito general (conexiones o cualquier objeto caro), utilizo algo como:

def pool(ctor, limit=None): 
    local_pool = multiprocessing.Queue() 
    n = multiprocesing.Value('i', 0) 
    @contextlib.contextmanager 
    def pooled(ctor=ctor, lpool=local_pool, n=n): 
     # block iff at limit 
     try: i = lpool.get(limit and n.value >= limit) 
     except multiprocessing.queues.Empty: 
      n.value += 1 
      i = ctor() 
     yield i 
     lpool.put(i) 
    return pooled 

que construye con pereza, tiene un límite opcional, y debe generalizar a cualquier caso de uso I puedo pensar Por supuesto, esto supone que realmente necesita la agrupación de cualquier recurso, que puede no tener para muchos gustos SQL modernos. Uso:

# in main: 
my_pool = pool(lambda: do_something()) 
# in thread: 
with my_pool() as my_obj: 
    my_obj.do_something() 

Esto asume que cualquier cosa que crea ctor objeto tiene un destructor apropiada si es necesario (algunos servidores no matan a los objetos de conexión a menos que se cierran de forma explícita).

+0

Olvidaste dos cosas: 1. 'yield i' puede generar excepciones, por lo que debes envolverlo con try ... excepto. 2. 'lpool.put (i)' puede devolver el objeto en un estado incorrecto (como la conexión db con la transacción abierta) – socketpair

+0

La excepción producida en realidad debe ser manejada por el administrador de contexto. No importa cómo se sale del contexto (excepción o no), se ejecutará el resto de la función. Pero sí, si estás haciendo manipulaciones con estado en el DB, manejarlo en el bit de la función post-rendimiento sería una buena idea. – metaperture

+0

En la práctica, usar el objeto pool en la publicación editada de Chris es probablemente mejor, pero para aquellos que buscan aprender a implementar pools en general, creo que este es un buen ejemplo. – metaperture

1

Respondiendo a un hilo antiguo, pero la última vez que lo comprobé, MySQL ofrece la agrupación de conexiones como parte de sus controladores.

Usted puede comprobar a cabo en:

https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html

De TFA, Suponiendo que desea abrir un pool de conexiones de forma explícita (como OP había declarado):

dbconfig = { "database": "test", "user":"joe" } 
cnxpool = mysql.connector.pooling.MySQLConnectionPool(pool_name = "mypool",pool_size = 3, **dbconfig) 

A continuación, se accede a este grupo solicitándolo desde el grupo a través de la función get_connection().

cnx1 = cnxpool.get_connection() 
cnx2 = cnxpool.get_connection() 
Cuestiones relacionadas