পাইথন গ্রন্থাগার মডিউলে ডাটাবেস সংযোগগুলি কীভাবে মোকাবেলা করতে হয়


23

আমি পাইথনে একটি লাইব্রেরি তৈরি করেছি যাতে একটি ডাটাবেস অ্যাক্সেস করার জন্য ফাংশন রয়েছে। এটি তৃতীয় পক্ষের অ্যাপ্লিকেশন ডাটাবেসের আশেপাশে একটি মোড়কের লাইব্রেরি, তৃতীয় পক্ষের অ্যাপ্লিকেশন কোনও শালীন এপিআই সরবরাহ করে না এই কারণে লিখিত। এখন আমি মূলত প্রতিটি ফাংশনটি ফাংশন কলটির সময়কালের জন্য একটি ডাটাবেস সংযোগটি খুলতে দেব যা ঠিক ছিল, যতক্ষণ না আমার প্রোগ্রাম যুক্তিটি ফাংশনগুলিতে নেস্টেড কলগুলি ব্যবহার করে যেখানে আমি তখন কয়েক হাজার বার একটি নির্দিষ্ট ফাংশন কল করব। এটি খুব অভিনয় ছিল না। এটি প্রোফাইলিংয়ে দেখানো হয়েছিল যে ওভারহেড ডাটাবেস সংযোগ সেটআপে ছিল - প্রতি ফাংশন কল প্রতি একবার। সুতরাং আমি ফাংশন (গুলি) এর মধ্যে থেকে ওপেন সংযোগটি নিজেই মডিউলে স্থানান্তরিত করেছি, যাতে লাইব্রেরি মডিউলটি আমদানি করা হলে ডাটাবেস সংযোগটি খোলা যায়। এটি আমাকে একটি গ্রহণযোগ্য অভিনয় দিয়েছে।

এ সম্পর্কে এখন আমার দুটি প্রশ্ন আছে। প্রথমত, আমার কি উদ্বিগ্ন হওয়া দরকার যে আমি আর স্পষ্টভাবে ডেটাবেস সংযোগটি বন্ধ করে দিচ্ছি না এবং কীভাবে আমি এই সেট-আপ দিয়ে স্পষ্টভাবে এটি করতে পারি? দ্বিতীয়ত, আমি যা করেছি তা কি ভাল অনুশীলনের ক্ষেত্রের কাছাকাছি গিয়ে পড়ে এবং অন্যথায় কীভাবে আমি এটির কাছে যেতে পারি?


1
একটি openConnফাংশন সরবরাহ করুন এবং ব্যবহারকারীকে তাদের যে প্রতিটি ফাংশন তারা কল করবেন তা এটি পাস করুন, যাতে তারা কোনও withবিবৃতিতে বা যে কোনও
কিছুতে

1
আমি জোজফেগের সাথে একমত, একটি শ্রেণি তৈরির কথা বিবেচনা করুন যা নির্মাণকারীর মধ্যে ডিবি সংযোগ খোলে এবং প্রস্থান করার সময় সংযোগটি বন্ধ করে দেয়
নিক বার্নস

উত্তর:


31

এটি আপনি যে লাইব্রেরিটি ব্যবহার করছেন তার উপর এটি নির্ভর করে। তাদের মধ্যে কেউ কেউ নিজের থেকে সংযোগটি বন্ধ করে দিতে পারে (দ্রষ্টব্য: আমি বিল্টইন স্ক্লাইট 3 লাইব্রেরিটি পরীক্ষা করেছিলাম এবং এটি হয় না)। পাইথন একজন ডেস্ট্রাক্টরকে কল করবে যখন কোনও বস্তু সুযোগের বাইরে চলে যাবে এবং এই লাইব্রেরিগুলি এমন একটি ডেস্ট্রাক্টর বাস্তবায়ন করতে পারে যা সংযোগগুলি নিখুঁতভাবে বন্ধ করে দেয়।

তবে, তা নাও হতে পারে! অন্যদের মতামত অনুসারে আমি এটিকে কোনও বস্তুতে আবদ্ধ করার পরামর্শ দেব।

class MyDB(object):

    def __init__(self):
        self._db_connection = db_module.connect('host', 'user', 'password', 'db')
        self._db_cur = self._db_connection.cursor()

    def query(self, query, params):
        return self._db_cur.execute(query, params)

    def __del__(self):
        self._db_connection.close()

এটি শুরুতে আপনার ডাটাবেস সংযোগটি ইনস্ট্যান্ট করে তুলবে এবং যখন আপনার অবজেক্টটি তাত্ক্ষণিকভাবে স্থাপন করা হয়েছিল তখন সুযোগের বাইরে চলে যাবে it দ্রষ্টব্য: আপনি যদি মডিউল স্তরে এই অবজেক্টটি ইনস্ট্যান্ট করেন তবে এটি আপনার সম্পূর্ণ প্রয়োগের জন্য অব্যাহত থাকবে। যদি না এটি উদ্দেশ্য না করা হয় তবে আমি আপনার ডাটাবেস ফাংশনগুলিকে নন-ডাটাবেস ফাংশন থেকে আলাদা করার পরামর্শ দেব।

ভাগ্যক্রমে, পাইথন ডেটাবেস এপিআই মানক করেছে , সুতরাং এটি আপনার জন্য সমস্ত সম্মতিজনক DBs এর সাথে কাজ করবে :)


কীভাবে আপনি এড়ানো selfযায় def query(self,?
সামায়ো

2
সংজ্ঞা এড়ানো? স্বতঃবর্গ যা কোনও শ্রেণি পদ্ধতির পরিবর্তে উদাহরণস্বরূপ পদ্ধতি হিসাবে সংজ্ঞা দেয়। আমি অনুমান করি আপনি ক্লাসে স্থিতিশীল সম্পত্তি হিসাবে ডাটাবেস তৈরি করতে পারেন, এবং তারপরে কেবল ক্লাসের পদ্ধতিগুলি (কোথাও কোনও স্ব-প্রয়োজন নেই) ব্যবহার করতে পারেন তবে ডাটাবেসটি কেবল শ্রেণীর কাছে বৈশ্বিক হবে, কেবল এটির ব্যক্তিগত স্বীকৃতি নয়।
ট্র্যাভিস

হ্যাঁ, কারণ আমি সাধারণ উদাহরণ হিসাবে আপনার উদাহরণটি ব্যবহার করার চেষ্টা করেছি db.query('SELECT ...', var)এবং এটি তৃতীয় যুক্তির প্রয়োজন বলে অভিযোগ করেছে।
সামায়ো

@ স্যামসন, আপনাকে MyDBপ্রথমে অবজেক্টটি ইনস্ট্যান্ট করতে হবে :db = MyDB(); db.query('select...', var)
কাওবার্ট

এটি বার্তা প্রতিরোধ করেছেResourceWarning: unclosed <socket.socket...
বব স্টেইন

3

ডাটাবেস সংযোগগুলি পরিচালনা করার সময় দুটি বিষয় সম্পর্কে উদ্বিগ্ন হতে হবে:

  1. একাধিক সংযোগ তাত্পর্য প্রতিরোধ, প্রতিটি ফাংশন একটি ডাটাবেস সংযোগ খোলা দেওয়া খারাপ অনুশীলন হিসাবে বিবেচনা করা হয়, ডাটাবেস সেশনের সীমাবদ্ধ সংখ্যা প্রদান করে, আপনি সেশন সমাপ্ত হবে; কমপক্ষে আপনার সমাধানটি মাপবে না, পরিবর্তে, সিঙ্গলটন প্যাটার্নটি ব্যবহার করুন, আপনার শ্রেণিটি একবার একবার ইনস্ট্যান্ট করা হবে, এই প্যাটার্নটি সম্পর্কে আরও তথ্যের জন্য লিঙ্কটি দেখুন

  2. অ্যাপ্লিকেশনটি প্রস্থান করার পরে সংযোগটি বন্ধ করে দেওয়া যাক, আপনি বলেননি এবং অ্যাপ্লিকেশনটির কমপক্ষে ডজন ডজন ঘটনাও একই রকম চলছে, প্রথমে সবকিছু ঠিকঠাক হয়ে যাবে, তবে আপনার ডাটাবেস সেশনগুলি শেষ হয়ে যাবে, এবং একমাত্র সমাধান fix ডাটাবেস সার্ভারটি পুনরায় চালু করা হবে যা কোনও লাইভ অ্যাপ্লিকেশনটির জন্য ভাল জিনিস নয় তাই যখনই সম্ভব সম্ভব একই সংযোগটি ব্যবহার করুন।

এই সমস্ত ধারণাকে দৃ .় করার জন্য নীচের উদাহরণটি দেখুন যা সাইকোপজি ২ কে মোড় দেয়

import psycopg2


class Postgres(object):
"""docstring for Postgres"""
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
            # normally the db_credenials would be fetched from a config file or the enviroment
            # meaning shouldn't be hardcoded as follow
            db_config = {'dbname': 'demo', 'host': 'localhost',
                     'password': 'postgres', 'port': 5432, 'user': 'postgres'}
            try:
                print('connecting to PostgreSQL database...')
                connection = Postgres._instance.connection = psycopg2.connect(**db_config)
                cursor = Postgres._instance.cursor = connection.cursor()
                cursor.execute('SELECT VERSION()')
                db_version = cursor.fetchone()

            except Exception as error:
                print('Error: connection not established {}'.format(error))
                Postgres._instance = None

            else:
                print('connection established\n{}'.format(db_version[0]))

        return cls._instance

    def __init__(self):
        self.connection = self._instance.connection
        self.cursor = self._instance.cursor

    def query(self, query):
        try:
            result = self.cursor.execute(query)
        except Exception as error:
            print('error execting query "{}", error: {}'.format(query, error))
            return None
        else:
            return result

    def __del__(self):
        self.connection.close()
        self.cursor.close()

1
নমস্কার! আপনার উত্তর করার জন্য আপনাকে ধন্যবাদ। তবে আমি যখন আমার ক্ষেত্রে এটি প্রয়োগ করার চেষ্টা করি তখন if Database._instance is None: NameError: name 'Database' is not defined। আমি কী বুঝতে পারি না Databaseএবং এটি কীভাবে ঠিক করতে পারি।
ইলিয়া রুসিন

1
ইলিয়ারুসিন এটি আমার দোষ ছিল, আসলে ডেটাবেস হ'ল একটি পিতা-মাতার শ্রেণি যেখানে আমি বিভিন্ন আরডিবিএমএস হ্যান্ডলিংয়ের জন্য সাধারণ পদ্ধতি রাখি যেহেতু আমি কেবল পোস্টগ্র্রেসকেই সংযুক্ত করি না। তবে ভুলের জন্য দুঃখিত এবং আমি আশা করি যে সংশোধিত সংস্করণটি আপনার পক্ষে কার্যকর হতে পারে, বিনা দ্বিধায় আপনার কোডটি সংযুক্ত করে আপনার প্রয়োজনে দ্বিধা বোধ করবেন না।
পোনাচ

যদি আমি বারবার Postgres.query(Postgres(), some_sql_query)একটি whileলুপে কল করতাম তবে তা কি প্রতিটি পুনরাবৃত্তির মধ্যে সংযোগটি খোলা এবং বন্ধ করে দেবে, বা whileপ্রোগ্রামটি শেষ না হওয়া অবধি লুপের পুরো সময়ের জন্য উন্মুক্ত রাখবে ?

@ মিশেল সংযোগ ক্লাসটি একটি সিঙ্গলটন হিসাবে প্রয়োগ করা হয়েছে, সুতরাং এটি কেবল একবারে ইনস্ট্যান্ট করা হবে তবে সামগ্রিকভাবে আমি প্রস্তাবিত কলের বিপরীতে সুপারিশ করব, পরিবর্তে এটি পরিবর্তনশীল হিসাবে শুরু করব
পোনাচ

1
@ পোনাচ ধন্যবাদ, আমি যা অর্জন করতে চেয়েছিলাম ঠিক তা করে। আমি আপনার কোডটি কিছুটা মানিয়ে নিয়েছি এবং আপনার query()ফাংশনে একটি আপডেটের বিবৃতিটি ব্যবহার করার চেষ্টা করেছি , তবে "অ্যাপ্লিকেশন" সমান্তরালে আমার অ্যাপটি চালানোর সময় আমার কোডটিতে সমস্যা আছে বলে মনে হচ্ছে। আমি এটি সম্পর্কে একটি পৃথক প্রশ্ন করেছি: সফ্টওয়্যারেনজেনারিং.স্ট্যাকেক্সেঞ্জার

2

আপনার অবজেক্টের জন্য কনটেক্সট ম্যানেজারের দক্ষতা সরবরাহ করা আকর্ষণীয় হবে। এর অর্থ আপনি এইরকম একটি কোড লিখতে পারেন:

class MyClass:
    def __init__(self):
       # connect to DB
    def __enter__(self):
       return self
    def __exit__(self):
       # close the connection

এটি আপনাকে স্টেটমেন্টের সাথে ক্লাসটি কল করে স্বয়ংক্রিয়ভাবে ডাটাবেসের সাথে সংযোগ বন্ধ করার একটি সহজ উপায় অফার করবে:

with MyClass() as my_class:
   # do what you need
# at this point, the connection is safely closed.

-1

এ নিয়ে ভাবতে অনেক দিন। আজ, আমি উপায় খুঁজে পেয়েছি। আমি জানি না এটি সবচেয়ে ভাল উপায়। আপনি নামের সাথে একটি ফাইল তৈরি করুন: কান.পি, এবং এটি /usr/local/lib/python3.5/site-packages/conn/ ফোল্ডারে সংরক্ষণ করুন। আমি ফ্রিবিএসডি ব্যবহার করি এবং এটি আমার সাইট-প্যাকেজ ফোল্ডারের পথ। আমার সংযোগে: সংযোগ = "ডিবি নাম = সর্বজনীন ব্যবহারকারী = পাসওয়ার্ডের পাসওয়ার্ড = 12345678"

`` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` `` ` এবং স্ক্রিপ্টে আমি সংযোগটি কল করতে চাই, আমি লিখি:

আমদানি psycopg2 আমদানি psycopg2.extras আমদানি psycopg2.exferences

সংযোগ আমদানি সংযোগ থেকে চেষ্টা করুন: সংযুক্ত = psycopg2.con সংযুক্ত (কানকনকন) ব্যতীত: পৃষ্ঠা = "ডাটাবেস অ্যাক্সেস করতে পারবেন না"

কার = সংযোগকারী ()

এবং ব্লাহ ব্লা ....

আমি এই দরকারী আশা করি

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.