ما هو الحل الأفضل لتجميع اتصال قاعدة البيانات في بيثون؟

StackOverflow https://stackoverflow.com/questions/98687

سؤال

لقد قمت بتطوير بعض الفئات المخصصة المشابهة لـ DAO لتلبية بعض المتطلبات المتخصصة جدًا لمشروعي، وهي عملية من جانب الخادم لا تعمل داخل أي نوع من الإطارات.

يعمل الحل بشكل رائع باستثناء أنه في كل مرة يتم فيها تقديم طلب جديد، أقوم بفتح اتصال جديد عبر MySQLdb.connect.

ما هو أفضل حل "للدخول" لتحويل هذا إلى استخدام تجمع الاتصالات في بيثون؟إنني أتخيل شيئًا مثل حل DBCP المشترك لـ Java.

العملية طويلة الأمد وتحتوي على العديد من المواضيع التي تحتاج إلى تقديم طلبات، ولكن ليس كلها في نفس الوقت...على وجه التحديد، يقومون بالكثير من العمل قبل فترات قصيرة من كتابة جزء كبير من نتائجهم.

تم التعديل للإضافة:وبعد مزيد من البحث وجدت anitpool.py والذي يبدو لائقًا، ولكن بما أنني جديد نسبيًا على لغة بايثون، أعتقد أنني أريد فقط التأكد من أنني لا أفتقد حلًا أكثر وضوحًا/أكثر اصطلاحيًا/أفضل.

هل كانت مفيدة؟

المحلول

IMO، "الحل الأكثر وضوحًا/الاصطلاحية/الأفضل" هو استخدام ORM موجود بدلاً من اختراع فئات تشبه DAO.

يبدو لي أن ORM أكثر شيوعًا من اتصالات SQL "الأولية".لماذا؟لأن بايثون يكون OO، والتعيين من صف SQL إلى الكائن يكون من الضروري للغاية.لا توجد حالات كثيرة تتعامل فيها مع صفوف SQL التي لا يتم تعيينها لكائنات Python.

اعتقد انه SQLAlchemy أو كائن SQL (وتجميع الاتصالات المرتبطة به) هو الحل البايثوني الأكثر اصطلاحًا.

التجميع كميزة منفصلة ليس شائعًا جدًا لأن لغة SQL النقية (بدون تعيين الكائنات) لا تحظى بشعبية كبيرة بالنسبة لهذا النوع من العمليات المعقدة وطويلة الأمد التي تستفيد من تجميع الاتصالات.نعم، SQL نقية يكون المستخدمة، ولكنها تستخدم دائمًا في التطبيقات الأبسط أو الأكثر تحكمًا حيث لا يكون التجميع مفيدًا.

أعتقد أنه قد يكون لديك بديلان:

  1. قم بمراجعة الفصول الدراسية الخاصة بك لاستخدام SQLAlchemy أو SQLObject.على الرغم من أن هذا يبدو مؤلمًا في البداية [يضيع كل هذا العمل]، إلا أنه يجب أن تكون قادرًا على الاستفادة من كل التصميم والفكر وهو مجرد تمرين في اعتماد حل ORM وتجميع الاستخدام على نطاق واسع.
  2. قم بإنشاء تجمع الاتصال البسيط الخاص بك باستخدام الخوارزمية التي حددتها - مجموعة أو قائمة بسيطة من الاتصالات التي تتنقل عبرها.

نصائح أخرى

في الخلية؟

أود أن أقول لا تهتم بتجميع الاتصال.غالبًا ما تكون مصدرًا للمشاكل، ومع MySQL لن تقدم لك ميزة الأداء التي تأمل فيها.قد يتطلب اتباع هذا الطريق الكثير من الجهد - سياسيًا - نظرًا لوجود الكثير من أفضل ممارسات التلويح باليد وإسهاب الكتب المدرسية في هذا المجال حول مزايا تجميع الاتصالات.

تعد تجمعات الاتصال مجرد جسر بين عصر ما بعد الويب للتطبيقات عديمة الجنسية (على سبيل المثال.بروتوكول HTTP) وعصر ما قبل الويب لتطبيقات معالجة الدفعات طويلة الأمد.نظرًا لأن الاتصالات كانت باهظة الثمن في قواعد بيانات ما قبل الويب (حيث لم يكن أحد يهتم كثيرًا بالمدة التي يستغرقها إنشاء الاتصال)، فقد ابتكرت تطبيقات ما بعد الويب مخطط تجمع الاتصال هذا بحيث لا تتسبب كل ضربة في تحمل تكاليف المعالجة الضخمة هذه على نظام RDBMS.

نظرًا لأن MySQL عبارة عن نظام RDBMS لعصر الويب، فإن الاتصالات خفيفة الوزن وسريعة للغاية.لقد كتبت العديد من تطبيقات الويب ذات الحجم الكبير والتي لا تستخدم تجمع اتصال على الإطلاق لـ MySQL.

وهذا تعقيد قد تستفيد من الاستغناء عنه، طالما لا توجد عقبة سياسية يجب التغلب عليها.

لف فئة الاتصال الخاصة بك.

قم بتعيين حد لعدد الاتصالات التي تجريها.إرجاع اتصال غير مستخدم.اعتراض قريب لتحرير الاتصال.

تحديث:أضع شيئًا كهذا في dbpool.py:

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

موضوع قديم، ولكن للتجميع للأغراض العامة (الاتصالات أو أي كائن باهظ الثمن)، أستخدم شيئًا مثل:

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

الذي يتم إنشاؤه بتكاسل، وله حد اختياري، ويجب تعميمه على أي حالة استخدام يمكنني التفكير فيها.بالطبع، يفترض هذا أنك تحتاج حقًا إلى تجميع أي مورد، وهو ما قد لا تحتاجه للعديد من أمثال SQL الحديثة.الاستخدام:

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

يفترض هذا أن أي كائن ينشئه ctor لديه أداة تدمير مناسبة إذا لزم الأمر (بعض الخوادم لا تقتل كائنات الاتصال ما لم يتم إغلاقها بشكل صريح).

لقد كنت أبحث عن نفس النوع من الشيء.

لقد وجدت pysqlpool و ال وحدة تجمع sqlalchemy

يعد إنشاء تجمع الاتصال الخاص بك فكرة سيئة إذا قرر تطبيقك البدء في استخدام مؤشرات الترابط المتعددة.يعد إنشاء تجمع اتصال لتطبيق متعدد الخيوط أكثر تعقيدًا بكثير من إنشاء تجمع اتصال لتطبيق واحد.يمكنك استخدام شيء مثل PySQLPool في هذه الحالة.

إنها أيضًا فكرة سيئة استخدام ORM إذا كنت تبحث عن الأداء.

إذا كنت ستتعامل مع قواعد بيانات ضخمة/ثقيلة يجب أن تتعامل مع الكثير من الاختيار والإدراج والتحديثات والحذف في نفس الوقت ، فأنت ستحتاج إلى الأداء ، مما يعني أنك ستحتاج إلى SQL مخصص لتحسين البحث وقفل أوقات.مع ORM، لا تتمتع عادةً بهذه المرونة.

لذا، نعم، يمكنك إنشاء تجمع الاتصال الخاص بك واستخدام ORMs ولكن فقط إذا كنت متأكدًا من أنك لن تحتاج إلى أي شيء مما وصفته للتو.

ردًا على موضوع قديم ولكن في المرة الأخيرة التي قمت فيها بالتحقق، يقدم MySQL تجميع الاتصال كجزء من برامج التشغيل الخاصة به.

يمكنك التحقق منها في:

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

من TFA، بافتراض أنك تريد فتح تجمع اتصال بشكل صريح (كما ذكر OP):

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

يتم بعد ذلك الوصول إلى هذا التجمع عن طريق الطلب من التجمع من خلال وظيفة get_connection().

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

يستخدم DBUtils, وبسيطة وموثوقة.

pip install DBUtils
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top