تَنفيذُ ذاكرةِ التَخزينِ المُؤقتِ العموميةِ والفرديةِ

مكتمل

يمكنك استخدامُ التخزينِ المؤقتِ لتحسين أداء التعليمات البرمجية الخاصة بك. تزداد الفوائدُ للبياناتِ أو التعليماتِ البرمجيةِ المستخدمةِ بشكلٍ متكررٍ. يمكنك تنفيذُ التخزين المؤقت العمومي على جلسة عميلٍ معينة أو تطبيقه على كافة العملاء على الخادم. في بعض السيناريوهات، يمكنك استخدام التخزين المؤقت العالمي للمعلمات الإضافية في توقيع الطريقة لأن توقيعات الطريقة غير قابلة للتغيير باستخدام الامتدادات.

مهم

يجب التعاملُ مَع التخزينِ المؤقتِ بعنايةٍ لأنَّه يؤثِّر على استهلاك الذاكرة. يخزنُ التخزين المؤقت العالمي القيم في الذاكرة، وكمطورٍ أنت مسؤول عَن تحديثِ وإزالة البيانات القديمة من ذاكرةِ التخزينِ المؤقتِ. يمكن أن يؤثرَ تجاهلَ تنظيفِ التخزين المؤقت العالمي سلبًا على الأداء.

تعتمِدُ أفضل الممارسات لتنفيذ التخزين المؤقت على حالاتِ الاستخدامِ الخاصة بك.

SysGlobalCache وsingleton

يشير SysGlobalCache وsingleton إِلى ذاكرة تخزين مؤقتٍ لجلسة عميلٍ واحدٍ لا يمكن الوصول إليها في سلاسل رسائل النظام الأخرى. يقوم النظام بتنظيف ذاكرة التخزين المؤقت هذه عند اكتمال جلسة العميل، ولكن من الأفضل تنظيف ذاكرة التخزين المؤقت بعد استخدامها.

يمكنك إنشاء SysGlobalCache لمثيل من فئة SysGlobalCache، ولكننا نوصي بإنشائه من فئات النظام التالية بحيث يكون التنظيف أسهل:

  • من فئة التطبيق باستخدام متغير نظام appl
  • من فئة ClassFactory باستخدام متغير نظام classFactory
  • من فئة المعلومات باستخدام متغير نظام Infolog

تم بالفعل تعريف globalCache لجميع فئات النظام المدرجة ويمكنك استخدامها.

تخزن فئة SysGlobalCache البيانات على مفتاح محدد، ولديها العديد من الطرق المستخدمة بشكل شائع:

  • Construct - يسمح لك بإنشاء مثيل جديد لـ SysGlobalCache. من خلال استخدام إحدى فئات النظام، مثل Application أو ClassFactory أو Info، تقوم هذه الطريقة بإنشاء مثيل تلقائيًا إذا لم يكن موجودًا بالفعل.
  • Get - يسترجع القيمة من مالكٍ ومفتاحٍ معينين.
  • Set - يعين القيمة لمالكٍ ومفتاحٍ معينين.
  • IsSet - التحقق مما إذا كانت ذاكرة التخزين المؤقت مخصصة لمالك ومفتاح محددين.

يقوم النظام بتخزين القيم في SysGlobalCache باستخدام المالك والمفتاح.

يوضح المثال التالي كيفية التحقق من وجود قيمة والحصول على قيمة وتعيين قيمة باستخدام SysGlobalCache.

internal final class RunnableClass1
{

    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        const str   mySysGlobalCacheKey   = 'MySysGlobalCacheKey';
        str         mySysGlobalCacheOwner = classStr(RunnableClass1);

        SysGlobalCache cache = classFactory.globalCache();

        container       cacheValue;

        if (cache.isSet(mySysGlobalCacheOwner, mySysGlobalCacheKey))
        {
            cacheValue = cache.get(mySysGlobalCacheOwner, mySysGlobalCacheKey);
        }
        else
        {
            cacheValue = ['MyValue'];

            cache.set(mySysGlobalCacheOwner, mySysGlobalCacheKey, cacheValue);
        }

        cache.remove(mySysGlobalCacheOwner, mySysGlobalCacheKey);

    }

}

يمكنك تحقيق نفس النتيجة باستخدام فئة Singleton (لجلسة المستخدم)، وهي عبارة عن مثيل للفئة التي ينشئها النظام داخل الفئة. أحد الاستخدامات الشائعة لهذه الحالة في تطبيقات التمويل والعمليات هو فئات الطيران، كما يوضح الكود التالي.

/// <summary>
/// When <c>AccountingFinTagFlight</c> is enabled, the uptake of financial tags functionality in the
/// Source Document and Accounting Framework is turned on. This allows documents implementing SDAF
/// to opt into processing of financial tags and provide their values during accounting distribution.
/// </summary>
public final class AccountingFinTagFlight extends Flight
{
    private static AccountingFinTagFlight singleton = new AccountingFinTagFlight();

    [Hookable(false)]
    protected boolean isEnabledByDefault()
    {
        return false;
    }

    [Hookable(false)]
    public static AccountingFinTagFlight instance()
    {
        return singleton;
    }

}

في هذا المثال من التطبيق القياسي، يقوم النظام بإنشاء مثيل لفئة AccountingFinTagFlight، ولكن مرة واحدة فقط لجلسة المستخدم.

تعرف حالة الاستخدام النهج، ويستخدم النظام SysGlobalCache وsingleton في التطبيق القياسي.

SysGlobalObjectCache

SysGlobalObjectCache عبارة عَن تخزين مؤقت مشترك مَع الخادم عبر كل جلسات عمل المستخدم على خادم معين.

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

يمكنك تعريف SysGlobalObjectCache على نطاق بدلاً من ربطه بمالك، كما هو الحال في SysGlobalCache.

الغرض من استخدام SysGlobalObjectCache هو تخزين القيم الثابتة في ذاكرة التخزين المؤقت لجميع الجلسات حتى لا يحتاج النظام إلى إعادة قراءتها أو حسابها لكل جلسة.

يوضح المثال التالي من تطبيقات التمويل والعمليات مثيل جديد لـ SysGlobalObjectCache. ومع ذلك، إذا تم إنشاء المثيل بالفعل، يشير النظام إلى SysGlobalObjectCache الموجود، وبالتالي يوجد مثيل واحد فقط، أو مثيل مفرد، في النظام.

public boolean findExternalDescription()
{
    boolean                     found;
    container                   cacheKey;
    container                   cacheValueExistsCheck;
    boolean                     continueProcessing;
    SysGlobalObjectCache        sysGlobalObjectCacheExistCheck = new SysGlobalObjectCache();

    cacheKey = [custVendAccountId, this.parmCustVendItemGroupId(), this.moduleType(), curExt()];

    //Check for existence
    cacheValueExistsCheck = sysGlobalObjectCacheExistCheck.find(CustVendExternalItemDescription::cacheScopeExistsCheck(), cacheKey);

    //We have not checked this combination before
    if (cacheValueExistsCheck == conNull())
    {
        if (CustVendExternalItem::existsForCustVendRelation(custVendAccountId, this.parmCustVendItemGroupId(), this.moduleType()))
        {
            // at least 1 record available for the customer/vendor group or customer/vendor
            continueProcessing = true;
        }
        else
        {
            // no record available for the customer/vendor group or customer/vendor
            continueProcessing = false;
        }
        sysGlobalObjectCacheExistCheck.insert(CustVendExternalItemDescription::cacheScopeExistsCheck(), cacheKey, [continueProcessing]);
    }
    else
    {
        [continueProcessing] = cacheValueExistsCheck;
    }

    if (continueProcessing)
    {
        [found, externalItemId, externalItemFreeTxt, custVendExternalItem] =
                CustVendExternalItemDescription::findExternalItemDescription(this.moduleType(), itemId, inventDim,
                                                                             custVendAccountId,this.parmCustVendItemGroupId());
    }

    return found;
}

يمكنك إزالة جميع الإدخالاتِ في SysGlobalObjectCache لخادمٍ عَن طريق تشغيلِ فئةٍ تستخدم عنوان URL التالي: https://[your finance and operations apps url]/?mi=SysClassRunner&cls=SysFlushAOD.

تقوم فئة SysFlushAOD بمسح كل ذاكرة التخزين المؤقت في SysGlobalObjectCache.

فئات السياق

مع الامتدادات، لا يمكنك تغيير توقيع الطريقة، مما يعني أنه لا يمكنك إضافة معلمات جديدة إلى طريقة موجودة.

‏‫‏‫‏‫‏‫‏‫ملاحظة

كما ذكرنا سابقًا، يمكنك تغيير توقيع الطريقة باستخدام الطبقات الزائدة عن طريق إضافة معلمة جديدة للطريقة. ومع ذلك، يمكنك توسيع توقيع الطريقة باستخدام سياق يمكن التخلص منه. عندما تقوم بتنفيذ IDisposable على فئة السياق، فإنه يجبرك على استخدام طريقة التخلص للتنظيف.

يؤدي المثال التالي إلى إنشاء فئة سياق لـ SalesPool بمعلمة واحدة تسمى myParameter.

internal final class MySalesPoolContext
{
    static MySalesPoolContext salesPoolContext;
 
    public  boolean myParameter;
  
    public void new()
    {
        salesPoolContext = this;
    }
 
    public void dispose()
    {
        salesPoolContext = null;
 
    }
  
    static public MySalesPoolContext current()
    {
        return  salesPoolContext;
 
    }

}

يمكنك الآن إضافة ملحق للأسلوب find الخاص بجدول SalesPool. يجب اختبار المعلمة الجديدة التي قمت بإنشائها في فئة السياق دون تغيير توقيع طريقة البحث على النحو التالي:

[ExtensionOf(tableStr(SalesPool))]
final class SalesPool_MB500_Extension
{
    static SalesPool find(SalesPoolId  _salesPoolId,
                          boolean     _forUpdate)
    {
        SalesPool  salesPool = next find(_salesPoolId, _forUpdate);

        MySalesPoolContext  salesPoolContext = MySalesPoolContext::current();

        if (salesPoolContext && salesPoolContext.myParameter)
        {
            // some code...
        }

        return salesPool;
    }

}

لأغراض الاختبار، يقوم المثال التالي بإنشاء فئة قابلة للتشغيل جديدة، ويمكنك تكوين متغير context parameter لاستدعاء طرق التخلص للتنظيف بعد استخدام الفئة.

internal final class MySalesPoolContextTest
{
    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        SalesPool           salesPool;
        MySalesPoolContext  mySalesPoolContext = new MySalesPoolContext();

        mysalesPoolContext.myParameter = true;

        salesPool = SalesPool::find('10');

        if (mySalesPoolContext)
        {
            mySalesPoolContext.dispose();
        }
    }

}

يساعدك إنشاء فئة سياق كمفردة على نقل المعلمات دون تغيير توقيع الطريقة.