স্ক্ল্যালেচেমি: সেশন পুনরায় ব্যবহার করা বনাম তৈরি করা


104

কেবলমাত্র একটি তাত্ক্ষণিক প্রশ্ন: এসকিউএএলএলএকমি একবার কল করার বিষয়ে কথা বলেছেsessionmaker() তবে Session()প্রতিবার আপনার ডিবি-র সাথে কথা বলার জন্য ফলাফল শ্রেণিকে কল করা । আমার জন্য এর অর্থ দ্বিতীয়টি আমি আমার প্রথম session.add(x)বা অনুরূপ কিছু করব, আমি প্রথমে করব would

from project import Session
session = Session()

আমি এখন অবধি যা করেছি তা হ'ল একবারsession = Session() আমার মডেলটিতে কল করা এবং তারপরে সর্বদা আমার আবেদনের যে কোনও জায়গায় একই সেশনটি আমদানি করা। যেহেতু এটি একটি ওয়েব-অ্যাপ্লিকেশন তাই এর অর্থ সাধারণত একই রকম হয় (যেমন একটি দৃশ্য কার্যকর করা হয়)।

তবে কোথায় পার্থক্য? আমার ফাংশন শেষ না হওয়া অবধি আমার ডেটাবেস স্টাফের জন্য সর্বদা একটি সেশন ব্যবহার করা এবং তার পরের বার আমি আমার ডিবির সাথে কথা বলতে চাইলে কোনও নতুন তৈরি করার অসুবিধা কী?

আমি পেয়েছি যে আমি যদি একাধিক থ্রেড ব্যবহার করি তবে প্রত্যেকেরই নিজস্ব সেশনটি পাওয়া উচিত। তবে ব্যবহার করে scoped_session(), আমি ইতিমধ্যে নিশ্চিত হয়েছি যে সমস্যাটি নেই I

আমার অনুমানগুলির কোনও ভুল আছে কিনা তা দয়া করে পরিষ্কার করুন।

উত্তর:


236

sessionmaker()এটি একটি কারখানা, এটি Sessionকেবলমাত্র এক জায়গায় নতুন বস্তু তৈরির জন্য কনফিগারেশন বিকল্প স্থাপনের জন্য উত্সাহিত করার জন্য । এটি alচ্ছিক, এটির জন্য আপনার ভারবস এবং অপ্রয়োজনীয় ব্যতীত Session(bind=engine, expire_on_commit=False)আপনি যখনই নতুন প্রয়োজন হবে ঠিক তত সহজে কল করতে পেরেছিলেন Sessionএবং আমি ক্ষুদ্র-স্কেল "সহায়তাকারীদের" প্রসার বন্ধ করতে চেয়েছিলাম যা প্রত্যেকে কিছুটা নতুন করে এই অনর্থক ইস্যুটির কাছে পৌঁছেছিল এবং আরও বিভ্রান্তিকর উপায়।

সুতরাং sessionmaker()আপনি তৈরি করতে সাহায্য শুধু একটি টুল Sessionবস্তু যখন আপনি তাদের প্রয়োজন।

পরবর্তী অংশ। আমি মনে করি প্রশ্নটি হ'ল Session()বিভিন্ন পয়েন্টে নতুন করে তৈরি করার মধ্যে পার্থক্য কী কেবল পুরো পথটি ব্যবহার করে। উত্তর, খুব বেশি না। Sessionআপনি যে সমস্ত বস্তুর মধ্যে রেখেছেন তার জন্য এটি একটি ধারক এবং তারপরে এটি একটি উন্মুক্ত লেনদেনের উপর নজর রাখে। এই মুহুর্তে আপনি কল করেছেন rollback()বা commit(), লেনদেন শেষ হয়েছে, এবং Sessionএসকিউএল পুনরায় নির্গত করার আহ্বান না করা পর্যন্ত এটির ডাটাবেসের সাথে কোনও সংযোগ নেই। আপনার ম্যাপযুক্ত অবজেক্টগুলিতে এটি যে লিঙ্কগুলি ধরে রেখেছে সেগুলি দুর্বল রেফারেন্সিং, শর্ত রয়েছে যে অবজেক্টগুলি মুলতুবি পরিবর্তনগুলি থেকে পরিষ্কার থাকে, তাই Sessionআপনার অ্যাপ্লিকেশন ম্যাপ করা অবজেক্টগুলির সমস্ত রেফারেন্স হারিয়ে ফেললে এমনকি সেই ক্ষেত্রে নিজেকে একেবারে নতুন অবস্থায় ফিরিয়ে দেয়। যদি আপনি এটির ডিফল্ট রেখে দেন"expire_on_commit"সেটিং, তারপরে সমস্ত বস্তু একটি প্রতিশ্রুতিবদ্ধতার পরে মেয়াদ শেষ হয়ে যায়। যদি এটি Sessionপাঁচ বা বিশ মিনিটের জন্য স্থায়ী হয়ে থাকে এবং আপনি পরের বার এটি ব্যবহার করার সময় ডাটাবেসে সমস্ত ধরণের জিনিস পরিবর্তন হয়ে যায়, পরের বার আপনি যখন সেই জিনিসগুলিতে অ্যাক্সেস করেন তখন তারা সমস্ত ব্র্যান্ডের নতুন অবস্থা লোড করবে যদিও তারা স্মৃতিতে বসে থাকলেও বিশ মিনিটের জন্য।

ওয়েব অ্যাপ্লিকেশনগুলিতে আমরা সাধারণত বলি, আরে আপনি Sessionবারবার একই অনুরোধ না করে প্রতিটি অনুরোধে একেবারে নতুন কেন করেন না । এই অনুশীলনটি নিশ্চিত করে যে নতুন অনুরোধটি "পরিষ্কার" শুরু হয়। পূর্ববর্তী অনুরোধ থেকে কিছু বস্তু যদি এখনও আবর্জনা সংগ্রহ না করে এবং আপনি যদি বন্ধ করে দিয়ে থাকেন "expire_on_commit"তবে পূর্বের অনুরোধটি থেকে কিছু স্থিতি এখনও ঘুরে বেড়াচ্ছে এবং সেই অবস্থাটি সম্ভবত বেশ পুরানো। আপনি যদি চালিয়ে যেতে expire_on_commitএবং স্পষ্টভাবে কল করতে commit()বা rollback()অনুরোধ শেষে সতর্ক হন, তবে এটি ঠিক আছে, তবে আপনি যদি একেবারে নতুন দিয়ে শুরু করেন Session, তবে আপনি পরিষ্কার শুরু করছেন এমন কোনও প্রশ্নও নেই। সুতরাং প্রতিটি অনুরোধ নতুন দিয়ে শুরু করার ধারণাSessionআপনি নতুন করে শুরু করছেন তা নিশ্চিত করার এবং is expire_on_commitচ্ছিকভাবে ব্যবহারিকভাবে ব্যবহার করার সহজ উপায় হ'ল এই পতাকাটি একটি ক্রিয়াকলাপের commit()মাঝখানে কল করে এমন একটি অপারেশনের জন্য অতিরিক্ত অতিরিক্ত এসকিউএল প্রচুর পরিমাণে আনতে পারে। এটি আপনার প্রশ্নের উত্তর দেয় কিনা তা নিশ্চিত নয়।

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


18
বাহ, এসকিউএলএলচেমি অংশে এটি আমার সমস্ত প্রশ্নের উত্তর দেয় এবং এমনকি ফ্লাস্ক এবং পিরামিড সম্পর্কে কিছু তথ্য যুক্ত করে! যুক্ত বোনাস: বিকাশকারীদের উত্তর;) আমি আশা করি আমি একবারের বেশি ভোট দিতে পারি। আপনাকে অনেক ধন্যবাদ!
জাভেক্স

একটি স্পষ্টতা যদি সম্ভব হয়: আপনি বলছেন এক্সপায়ার_অন_কমিট "" অতিরিক্ত এসকিউএল প্রচুর পরিমাণে লাগতে পারে "... আপনি আরও বিশদ দিতে পারেন? আমি ভাবলাম মেয়াদোত্তীর্ণ_কমিট কেবলমাত্র র‌্যামে যা ঘটেছিল তা কেবল ডেটাবেসে কী ঘটে তা নয়।
ভিকি

4
আপনি যদি একই সেশনটি আবার ব্যবহার করেন তবে এক্সপায়ার_কম_কমিট আরও এসকিউএল তৈরি করতে পারে এবং কিছু অজানা এখনও সেই সেশনে ঝুলছে, আপনি যখন এগুলি অ্যাক্সেস করবেন তখন আপনি তাদের প্রত্যেকের জন্য একক-সারি নির্বাচন পাবেন তারা প্রত্যেকে স্বতন্ত্রভাবে রিফ্রেশ করার কারণে নতুন লেনদেনের ক্ষেত্রে তাদের রাষ্ট্র।
zzzeek

4
হাই, @Zzeek চমৎকার উত্তরের জন্য ধন্যবাদ। আমি অজগরটিতে খুব নতুন এবং আমি স্পষ্ট করে বলতে চাই: 1) আমি যখন সেশন () পদ্ধতিতে এসকিউএল ট্রানজেকশন তৈরি করে নতুন "সেশন" তৈরি করি তখন কি আমি সঠিক বুঝতে পারি, তারপরে আমি / রোলব্যাক সেশন না করা পর্যন্ত লেনদেন খোলা থাকবে ? ২) সেশন () কি কোনও ধরণের সংযোগ পুল ব্যবহার করে বা প্রতিবার স্কেল করার জন্য নতুন সংযোগ তৈরি করে?
অ্যালেক্স গুরস্কি

28

চমৎকার zzzeek এর উত্তর ছাড়াও, দ্রুত নিক্ষিপ্ত, স্ব-বদ্ধ সেশনগুলি তৈরি করার জন্য এখানে একটি সাধারণ রেসিপি দেওয়া হয়েছে:

from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

@contextmanager
def db_session(db_url):
    """ Creates a context with an open SQLAlchemy session.
    """
    engine = create_engine(db_url, convert_unicode=True)
    connection = engine.connect()
    db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))
    yield db_session
    db_session.close()
    connection.close()

ব্যবহার:

from mymodels import Foo

with db_session("sqlite://") as db:
    foos = db.query(Foo).all()

4
আপনি কেবল একটি নতুন অধিবেশন তৈরি না করে একটি নতুন সংযোগ তৈরির কারণ রয়েছে কি?
২৩

সত্যই নয় - এটি মেকানিজমটি দেখানোর একটি দ্রুত উদাহরণ, যদিও পরীক্ষায় নতুন কিছু তৈরি করা বোধগম্য হয়, যেখানে আমি এই পদ্ধতির সর্বাধিক ব্যবহার করি। Functionচ্ছিক যুক্তি হিসাবে সংযোগের সাথে এই ফাংশনটি প্রসারিত করা সহজ হওয়া উচিত।
বেরিস্লাভ লোপাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.