मैंने लगभग पांच महीने पहले FastAPI के साथ रिपॉजिटरी पैटर्न को अपनाने के बारे में एक लेख लिखा था, और मुझे बहुत कुछ पढ़ने को मिला (धन्यवाद)। मैं अभी भी रिपोजिटरी पैटर्न का उपयोग कर सत्र प्रबंधन को संभालने के एक प्रभावी तरीके के बारे में लिखने आया हूं।
इससे पहले कि मैं इसमें सीधे कूदता, मैंने देखा कि उत्पादन पर, मुझे निम्न में से कोई भी त्रुटि मिलती है जब भी मेरे एपीआई लेनदेन करने की कोशिश कर रहे हैं जिसमें डेटाबेस को पढ़ना या लिखना शामिल है:
यह त्रुटि इंगित करती है कि एक अप्रतिबंधित लेनदेन प्रगति पर है जिसे किसी अन्य डेटाबेस संचालन के साथ आगे बढ़ने से पहले रोलबैक करने की आवश्यकता है।
इस त्रुटि का सबसे आम कारण एक डेटाबेस लेनदेन के दौरान होने वाला एक अनियंत्रित अपवाद है, जो लेनदेन को कमिट होने या ठीक से रोल बैक करने से रोकता है।
यह त्रुटि इंगित करती है कि आपके द्वारा डेटाबेस में किया गया कोई ऑपरेशन या अनुरोध अमान्य है या समर्थित नहीं है। इस त्रुटि के विभिन्न कारण हो सकते हैं, जिनमें निम्न शामिल हैं:
मुझे यकीन है कि आपके पास इस बारे में विचार हैं कि इन त्रुटियों को कैसे हल किया जा सकता है, हालांकि, मैं यह बताना चाहता हूं कि भले ही मैंने पहचान की कि समस्या क्या थी और इसे ठीक किया- समस्या बनी रहती है।
यदि आप उत्सुक हैं कि मैं कैसे उनका निवारण और समाधान करता हूं, तो आप निम्न चरणों का पालन करने पर विचार कर सकते हैं:
आइए देखें कि मैंने एक स्थायी समाधान पर कैसे काम किया जो मेरे लिए कारगर साबित हुआ है। मैं उस प्रोजेक्ट का उपयोग करने के लिए आगे बढ़ूंगा जिस पर मैंने काम किया था जब मैं रिपॉजिटरी पैटर्न का उपयोग करने का तरीका दिखा रहा था।
हमारे पास एक मॉड्यूल था जहां हमने निम्नलिखित कोड के साथ अपने ओआरएम बेस सत्र मिश्रण को संग्रहित किया था:
# SQLAlchemy Imports from sqlalchemy.orm import Session # Own Imports from config.database import SessionLocal from core.settings import ledger_settings class ORMSessionMixin: """Base orm session mixin for interacting with the database.""" def __init__(self): """ Get the next database session from the database pool. """ self.orm: Session = self.get_db().__next__() def get_db(self): """ This method creates a database session, yields it, rollback the transaction if there's an exception and then finally closes the session. Yields: db: scoped database session """ db = SessionLocal() try: yield db except Exception: db.rollback() finally: db.close()
इस समाधान के साथ समस्या यह थी कि यदि लेन-देन की प्रक्रिया में कोई अपवाद होता है (यह कुछ भी हो सकता है: एक उपयोगकर्ता बनाना, अपने बटुए को निधि देना, आदि) - अपवादों को ठीक से नियंत्रित नहीं किया जाता है, और पारगमन में डेटाबेस सत्र नहीं होता है रोलबैक प्राप्त करें।
तीन महीने के डिबगिंग और पैचिंग और बहुत सारे शोध के बाद, मैं आखिरकार सत्रों को संभालने का एक कुशल तरीका बनाने में सक्षम था।
# SQLAlchemy Imports import sqlalchemy from sqlalchemy.orm import Session # Own Imports from config.database.connection import SessionLocal class DatabaseSessionMixin: """Database session mixin.""" def __enter__(self) -> Session: self.db = SessionLocal() return self.db def __exit__(self, exc_type, exc_val, exc_tb): try: if exc_type is not None: self.db.rollback() except sqlalchemy.exc.SQLAlchemyError: pass finally: self.db.close() SessionLocal.remove() def use_database_session(): return DatabaseSessionMixin()
इस कोड में:
DatabaseSession
एक संदर्भ प्रबंधक वर्ग है जो सत्र को संभालता है और यह सुनिश्चित करता है कि यह ठीक से बंद हो और किसी त्रुटि के मामले में वापस लुढ़का हो।
__enter__
विधि सत्र को प्रारंभ करती है और इसे वापस करती है।
__exit__
विधि अपवादों की जांच करती है और अपवाद होने पर सत्र को वापस ले जाती है। इसके बाद यह सत्र को बंद कर देता है और इसे दायरे वाले सत्र से हटा देता है।
use_database_session
एक यूटिलिटी फंक्शन है जिसका उपयोग सत्र उपयोग को आसान बनाने के लिए डेकोरेटर या संदर्भ प्रबंधक के रूप में किया जा सकता है।
यहां एक उदाहरण दिया गया है कि आप use_database_session उपयोगिता फ़ंक्शन का उपयोग कैसे कर सकते हैं:
with use_database_session() as db: # perform logic that uses the session # ... # After exiting the context, the session will be automatically closed and removed from the scoped session.
उपरोक्त दृष्टिकोण सत्रों को संभालने के लिए एक स्वच्छ और अधिक कुशल तरीका प्रदान करता है और यह सुनिश्चित करता है कि त्रुटि के मामले में उन्हें ठीक से वापस ले लिया जाए या बंद कर दिया जाए। आइए आगे बढ़ते हैं कि आप ORM में डेटाबेस सत्र का उपयोग करते समय रिपॉजिटरी पैटर्न को कैसे लागू करते हैं।
# SQLAlchemy Imports import sqlalchemy from sqlalchemy.orm import Session class BaseRepository: def __init__(self, session: Session): self.db = session class UserRepository(BaseRepository): """Operations to interact with the `users` table in the database.""" def get(self, user_id: int) -> User: """This method gets a user from the database.""" user = ( self.db.query(User) .filter(User.id == user_id) .first() ) return user def create(self, name: str, email: str, password: str) -> User: """This method creates a user.""" user = User(name=name, email=email, password=password) self.db.add(user) self.db.commit() self.db.refresh(user) return user def update_user(self, user_id: int, updated_data: dict): """This method updates a user.""" user = self.get(user_id) if user: for key, value in updated_data.items(): setattr(user, key, value) self.db.commit() return user return None def delete_user(self, user_id): """This method deletes a user.""" user = self.get_user(user_id) if user: self.db.delete(user) self.db.commit() return True return False
इसके बाद उपरोक्त भंडार को आपके आवेदन की सेवा परत में एकीकृत करना होगा। मान लीजिए कि आपके पास एक सेवा कार्य है जो उपयोगकर्ता खाता बनाता है; यहां बताया गया है कि आप इसे हमारी नई पद्धति का उपयोग करके कैसे करेंगे:
# Apps Imports from apps.users.models import User from apps.users.repo import UserRepository from apps.users.schemas.auth import UserCreate # Config Imports from config.security.hashers import password from config.database.session_mixin import use_database_session async def create_user(user: UserCreate) -> User: """ This function creates a new user in the database. :param user: schemas.UserCreate :type user: schemas.UserCreate :return: The user object """ with use_database_session() as db: users_repo = UserRepository(db) user = users_repo.create( user.name, user.email, password.hash(user.password) ) return user
उपरोक्त पैटर्न आपको विरासत में मिले डेटाबेस सत्र का लाभ उठाते हुए डेटाबेस संचालन को रिपॉजिटरी कक्षाओं में समाहित करने की अनुमति देगा। यह आपके ORM मॉडल और रिपॉजिटरी लॉजिक के बीच एक स्पष्ट अलगाव भी प्रदान करता है।
अंत में, बैकएंड सिस्टम बनाते समय सत्रों का कुशल संचालन महत्वपूर्ण है।
डेटाबेस लेनदेन के दौरान होने वाली sqlalchemy.exc.PendingRollbackError
और sqlalchemy.exc.InvalidRequestError
जैसी त्रुटियां डेटा असंगतता और एप्लिकेशन विफलताओं का कारण बन सकती हैं यदि ठीक से संभाला न जाए।
सिस्टम की अखंडता और विश्वसनीयता को बनाए रखने के लिए इन त्रुटियों की पहचान करना और उनका समाधान करना महत्वपूर्ण है।
सत्र प्रबंधन से संबंधित मुद्दों को हल करने के लिए, मजबूत रणनीतियों को लागू करना आवश्यक है। एक दृष्टिकोण संदर्भ प्रबंधकों का उपयोग करना है, जैसे कि DatabaseSessionMixin
जिसे हमने लेख में प्रदर्शित किया है।
यह संदर्भ प्रबंधक सुनिश्चित करता है कि अपवादों के मामले में सत्र ठीक से खुले, बंद और लुढ़के हुए हैं। संदर्भ प्रबंधक के भीतर सत्र तर्क को समाहित करके, आप सत्र प्रबंधन को सुव्यवस्थित कर सकते हैं और त्रुटि से निपटने में सुधार कर सकते हैं।
इसके अतिरिक्त, एप्लिकेशन के सर्विस लेयर में रिपॉजिटरी पैटर्न को एकीकृत करने से सेशन हैंडलिंग की दक्षता में और वृद्धि हो सकती है।
डेटाबेस ऑपरेशंस को रिपॉजिटरी क्लासेस में अलग करके और संदर्भ प्रबंधक से विरासत में मिले सत्र का लाभ उठाकर, आप क्लीनर कोड संगठन प्राप्त कर सकते हैं और ORM मॉडल और रिपॉजिटरी लॉजिक के बीच स्पष्ट अलगाव बनाए रख सकते हैं।
कुल मिलाकर, कुशल सत्र प्रबंधन डेटा स्थिरता बनाए रखने, त्रुटियों को रोकने और बैकएंड सिस्टम की स्थिरता सुनिश्चित करने के लिए महत्वपूर्ण है।
सर्वोत्तम प्रथाओं का पालन करके, जैसे कि संदर्भ प्रबंधकों का उपयोग करना और रिपॉजिटरी पैटर्न को अपनाना, डेवलपर्स मजबूत और विश्वसनीय सिस्टम बना सकते हैं जो सत्रों को प्रभावी ढंग से प्रबंधित करते हैं और डेटाबेस लेनदेन के दौरान त्रुटियों को संभालते हैं।
मैं गिग्स लिखने और सक्रिय रूप से अनुबंध भूमिकाओं की खोज करने के लिए खुला हूं जिसमें पायथन (Django, FastAPI, आदि) के साथ निर्माण शामिल है।