1s 8 تراکنش های منابع خارجی. مشتریان یکبار مصرف تقسیم بندی برای خریدهای تکراری هزینه کالا در سفارش

صرف نظر از گزینه عملیات انتخاب شده (فایل یا سرویس گیرنده-سرور)، سیستم 1C: Enterprise با استفاده از مکانیسم تراکنش با اطلاعات ذخیره شده در پایگاه داده کار می کند.

معامله- این یک توالی تقسیم ناپذیر از عملیات دستکاری داده ها از نظر تأثیر بر پایگاه داده است. همه یا هیچ است و پایگاه داده را از یک حالت سازگار به حالت سازگار دیگر می برد. اگر به دلایلی یکی از اقدامات تراکنش با شکست مواجه شود یا نوعی نقص سیستم رخ دهد، پایگاه داده به حالت قبل از شروع تراکنش برمی گردد (تراکنش به عقب برگشته است).

سیستم 1C: Enterprise به طور ضمنی تراکنش ها را هنگام انجام هر گونه اقدام مربوط به اصلاح اطلاعات ذخیره شده در پایگاه داده فراخوانی می کند. به عنوان مثال، تمام کنترل‌کننده‌های رویداد واقع در ماژول‌های شی و مجموعه رکورد مربوط به اصلاح داده‌های پایگاه داده در یک تراکنش فراخوانی می‌شوند. تراکنش همچنین اشیاء از انواع زیر را می خواند: مبادله PlanObject، DocumentObject، DictionaryObject، Plan of Type of CharacteristicsObject، Plan نوع انواع CalculationObject، Chart Of AccountsObject، BusinessProcessObject، TaskObject، SequenceRecordSet،RegisterInformationRecordSet، AccuulationRegisterInformationRecordSet, AccumulationRegisterRegisterRecordSet, AccumulationRegisterRegisterRecordSet,RecordscaleRecordingRecording. در همان زمان، در حالت قفل های مدیریت شده، یک قفل مشترک روی مقدار ثبت کننده برای مجموعه رکوردها و روی مقادیر فیلتر برای مجموعه رکورد یک ثبت اطلاعات مستقل تنظیم می شود.

در کنار این، توسعه دهنده می تواند از کار با تراکنش ها به صورت صریح استفاده کند. برای این کار از رویه های زمینه جهانی استفاده می شود. StartTransaction()، CommitTransaction() و CancelTransaction().

استفاده از فراخوان صریح تراکنش

روش StartTransaction()به شما امکان می دهد یک تراکنش را باز کنید. پس از آن، تمام تغییرات در اطلاعات پایگاه داده انجام شده توسط عبارات بعدی می تواند به طور کامل پذیرفته شود یا به طور کامل رد شود. برای پذیرش تمام تغییرات انجام شده، از روش استفاده کنید CommitTransaction(). برای لغو همه تغییرات ایجاد شده در یک تراکنش باز، از روش استفاده کنید CancelTransaction(). اگر تعداد فراخوانی روش StartTransaction()از تعداد فراخوانی های متد بیشتر است CommitTransaction()یا CancelTransaction()، سپس سیستم یک فراخوانی متد ضمنی برقرار می کند CancelTransaction()در موارد زیر:

● در پایان اجرای زبان داخلی (کنترل کننده رویداد، اتصال خارجی، اتوماسیون-سرور).

● هنگام انتقال کنترل از سرور به کلاینت.

اگر تعداد فراخوانی روش CommitTransaction() یا CancelTransaction()از تعداد فراخوانی های متد بیشتر است StartTransaction()، سپس هنگامی که یک متد اضافی فراخوانی می شود CommitTransaction()یا CancelTransaction()یک استثنا پرتاب خواهد شد. بنابراین، طرح کار با یک تراکنش به طور کلی می تواند به شکل زیر باشد:

تلاش

StartTransaction();

// توالی عبارات

CommitTransaction();

استثنا

CancelTransaction();

پایان تلاش؛

هنگام استفاده از این طرح، به خاطر داشته باشید که همه خطاهایی که هنگام کار با پایگاه داده رخ می دهد به یک شکل توسط سیستم مدیریت نمی شود. به طور کلی تمام خطاهای پایگاه داده را می توان به دو دسته تقسیم کرد:

● غیر قابل بازیابی،

● قابل بازیابی

خطاهای غیر قابل جبرانخطاهایی هستند که ممکن است عملکرد عادی سیستم 1C: Enterprise را مختل کنند، به عنوان مثال، ممکن است داده ها خراب شوند. اگر خطای غیرقابل جبرانی رخ دهد، اجرای سیستم 1C: Enterprise در هر صورت خاتمه می یابد. اگر در حین اجرای تراکنش خطای غیرقابل جبرانی رخ دهد، تمام تغییرات ایجاد شده در این تراکنش توسط سیستم لغو می شود.

خطاهای قابل بازیابیخطاهایی هستند که اختلالات جدی در عملکرد سیستم 1C: Enterprise ایجاد نمی کنند. در صورت بروز خطای قابل بازیابی، عملیات بیشتر سیستم را می توان ادامه داد. در این صورت البته خود عملیاتی که باعث خطا شده است متوقف می شود و استثنایی پرتاب می شود که توسط ساخت و ساز قابل رهگیری و پردازش است.

تلاش... استثنا... پایان تلاش.

تماس تراکنش تودرتو

به عنوان بخشی از یک تراکنش در حال انجام، می توانید به رویه ها دسترسی داشته باشید StartTransaction()، CommitTransaction()و CancelTransaction(). به عنوان مثال، الگوی فراخوانی زیر ممکن است استفاده شود:

StartTransaction();

StartTransaction();

CommitTransaction();

// تماس تراکنش تودرتو

StartTransaction();

CommitTransaction();

CommitTransaction();

با این حال، چنین تماسی به معنای شروع یک تراکنش جدید در چارچوب یک تراکنش در حال اجرا نیست.

توجه!1C: Enterprise از تراکنش های تودرتو پشتیبانی نمی کند.این بدان معنی است که تنها معامله از سطح بالا.

تمام تراکنش‌هایی که در داخل یک تراکنش از قبل باز شده فراخوانی می‌شوند، در واقع متعلق به همان تراکنش هستند و یک تراکنش تودرتو تشکیل نمی‌دهند. بنابراین، لغو تغییرات انجام شده در یک تراکنش تودرتو در نهایت منجر به خنثی شدن تغییرات در خود تراکنش تودرتو نمی شود، بلکه منجر به خنثی شدن همه تغییرات در تراکنش سطح بالا می شود. در عین حال، تعهدات انجام شده در یک تراکنش تودرتو نادیده گرفته می شود.

تأثیر تراکنش ها بر عملکرد اشیاء برنامه

به طور کلی، اشیاء نرم افزاری مورد استفاده توسط 1C: Enterprise برای تراکنش های پایگاه داده کاملاً "شفاف" هستند. به عبارت دیگر تراکنش های پایگاه داده را می توان در هنگام اجرا فراخوانی کرد روش های مختلف اشیاء برنامهبا این حال، به عنوان مثال، اقدامات انجام شده توسط پایگاه داده زمانی که یک تراکنش به عقب برگردانده می شود، عموماً بر موارد مربوطه تأثیر نمی گذارد. نرم افزار اشیاء.

از این نتیجه می شود که هنگام لغو تراکنش های پایگاه داده، توسعه دهنده (در صورت لزوم) باید به طور مستقل از تغییر کافی در داده های مربوطه اطمینان حاصل کند. برنامه اشیاء. این کار را می توان با خواندن مجدد تمام داده های شی یا با تغییر برخی از ویژگی های شی برنامه انجام داد.

در این قانون استثنائاتی وجود دارد. با توجه به ویژگی های برنامه کاربردی قابل توجه اشیاء برنامه 1C: Enterprise، در برخی موارد بازگرداندن تغییرات ایجاد شده در پایگاه داده ممکن است همچنان بر مقادیر ویژگی های مربوطه تأثیر بگذارد. برنامه اشیاء. این در موارد زیر اتفاق می افتد:

● هنگامی که تراکنش لغو می شود، پرچم ارسال کننده سند، ارزشی را که قبل از شروع تراکنش داشت، بازیابی می کند.

● اگر شی در یک تراکنش ایجاد و نوشته شده باشد، پس از بازگرداندن تراکنش، مقدار مرجع پاک می شود.

● اگر شی خارج از تراکنش ایجاد شده باشد و از کد/شماره ای که به طور خودکار تولید می شود هنگام نوشتن آن در تراکنش استفاده شده باشد، پس از لغو تراکنش، کد/شماره پاک می شود.

2017-08-12

تراکنش های سفارشی برای نگهداری اشیاء OM ایجاد کنید.

مقدمه

من فکر می کنم که بسیاری از مشاوران SAP عملکردی با معامله نگهداری اشیاء مدیریت سازمانی مواجه شده اند. یعنی معامله PP01

استفاده از این تراکنش کاربر را قادر می‌سازد تا انواع اطلاعات مدیریت سازمانی را برای انواع شیئی که در فرآیندهای تجاری خودکار استفاده می‌شوند، مدیریت کند. اغلب، این تراکنش به عنوان یک نقطه ورودی واحد برای کار با انواع اشیاء مدیریت سازمانی استفاده می شود که در واقع، عمل چندان خوبی نیست. خوب، یا خیلی راحت نیست. اگرچه مسلماً رایج است. در مرحله بعد، من سعی خواهم کرد به شما بگویم که چه جایگزینی می تواند باشد.

جدول T77S0، گروه "TCODE"

هنگام پیکربندی اشیاء شی OM، به احتمال زیاد تنظیمات واقع در مسیر زیر را لمس خواهید کرد SPRO:

IMG: مدیریت پرسنل -> مدیریت سازمانی -> تنظیمات اولیه -> بهبود مدل داده -> حفظ انواع شی

در اینجا شما اشیاء OM جدید ایجاد می کنید، نام آنها را می گذارید، نمادها را انتخاب می کنید و تنظیماتی را برای آنها تعریف می کنید... در حال حاضر ما به گره علاقه مند هستیم " کلید نوع شی + تراکنش"

بخشی از نمای راه اندازی در مقابل شما باز می شود. T77S0با مقادیر گروه فیلتر شده

ارزش توجه به گروه را دارد TCODEکه در آن، اگر دقت کنید، می توانید نام فنی تراکنش هایی را که به احتمال زیاد مجبور به کار با آنها بوده اید، پیدا کنید. علاوه بر این، در ستون ارزشنوع شیئی که این یا آن معامله برای آن در نظر گرفته شده است مشخص شده است.

ویژگی این معاملات چیست؟

با استفاده از تراکنش‌هایی که برای نگهداری یک نوع خاص از شی طراحی شده‌اند، نیازی به انتخاب این نوع اشیاء ندارید که به‌طور پیش‌فرض در یک تراکنش در دسترس هستند. PP01. یعنی با اجرای مثلاً یک تراکنش PO09،شما بلافاصله شروع به کار با اشیاء از نوع می کنید L

ایجاد یک تراکنش جدید برای هدف مدیریت سازمانی خودتان

در یکی از یادداشت‌های قبلی‌ام، در مورد اینکه چگونه می‌توانید یک شی OM جدید بسازید + جستجوی ساختار را برای آن اضافه کنید، صحبت کردم

من از این مطالب دور نمی شوم. به عنوان یک نمایش، من یک تراکنش جدید برای حفظ شی ایجاد خواهم کرد 91.

تعریف یک نوع شی جدید در T77S0

نام تراکنش آینده را در نمای راه اندازی تعریف کنید T77S0

مقدار "ZP91M" در این مورد نام تراکنش آینده برای نگهداری شی است 91 . تغییرات خود را ذخیره کنید.

ایجاد یک تراکنش جدید برای حفظ شی OM

با یک معامله SE93یک تراکنش برای حفظ شی خود ایجاد کنید. در زیر یک کلیپ ویدیویی با دنباله ای از اقدامات است که باید برای ایجاد تراکنش مربوطه انجام شود

به مقادیری که برای فیلدها استفاده شده است توجه کنید برنامه, شماره صفحه نمایش,موضوع مجوز. اکنون یک معامله جدید را شروع کنید

کاربر این امکان را دارد که فقط با نوع خاصی از شی کار کند، که به تعبیری می توان آن را راحتی نامید، و در صورت تمایل، حداقل کردن اقدامات اضافی برای انتخاب شی مورد نظر.

آخرین باری که بررسی کردیم ساده ترین راهبا استفاده از زبان داخلی 1C. در تمرین معاملاتاغلب در ارتباط با طراحی استفاده می شود. این اجازه می دهد تا در صورت بروز خطا، اجرای کد ادامه یابد و همچنین یک پیغام خطای کافی برای کاربر صادر کند و اطلاعاتی را برای تجزیه و تحلیل بیشتر توسط مدیر سیستم در لاگ یا فایل گزارش بنویسد.

اگر به اسناد فنی یا دیسک ITS مراجعه کنیم، خواهیم دید که 1C روش زیر را برای سازماندهی یک تراکنش توصیه می کند.

تلاش //یک. شروع معامله StartTransaction(); //2. بلوکی از عملیات که در یک تراکنش انجام می شود. //3. اگر همه عملیات موفقیت آمیز بود، تراکنش را انجام دهید. CommitTransaction() ; استثنا //چهار. اگر هنگام اجرای کد خطایی رخ دهد، تراکنش را لغو می کنیم. CancelTransaction(); //5. در صورت لزوم، به گزارش بنویسید. //6. در صورت لزوم، پیامی را به کاربر نمایش دهید. EndTry

در واقع کد نیاز به توضیح خاصی ندارد. اگر در جریان است تلاش می کندبا اجرای کد تراکنش، خطایی رخ می دهد، بلافاصله وارد بلوک می شویم استثنا، یعنی قبل از روش CommitTransaction()ما فقط به آنجا نمی رسیم خوب، در استثناء، ما معامله را لغو می کنیم و در صورت نیاز، یک پیغام خطا نمایش می دهیم و اطلاعات را در لاگ می نویسیم. رفع خطاها در گزارش بسیار مطلوب است، به ویژه برای آن دسته از عملیاتی که بدون دخالت کاربر انجام می شوند (به عنوان مثال، وظایف برنامه ریزی شده). این امکان تجزیه و تحلیل بیشتر خطا را فراهم می کند. به جای نوشتن در گزارش، می توانید ترتیبی دهید که پیام ها از طریق ایمیل برای مدیر ارسال شوند.

اکنون، با داشتن دانش جدید، بیایید سعی کنیم کد مورد بحث در مقاله در مورد را اصلاح کنیم. اجازه دهید به شما یادآوری کنم که ما ورودی را در دایرکتوری در نظر گرفتیم محصولاتو در ثبت اطلاعات قیمتطبق طرح زیر:

&OnServerWithoutContext StartTransaction(); //نوشتن مورد جدیدمحصول = دایرکتوری ها محصولات. CreateElement(); تولید - محصول. نام = " سوراخ سوراخ " ; تولید - محصول. نوشتن() ؛ //قیمت را بنویسمجموعه رکورد =RegistersInfo. قیمت. CreateRecordSet() ; NewRecord = مجموعه رکورد. اضافه کردن() ؛ ورودی جدید. Period = CurrentDate() ; ورودی جدید. محصول = محصول ارتباط دادن؛ ورودی جدید. مبلغ = 100 ; RecordSet. نوشتن() ؛ CommitTransaction() ; پایان رویه

حالا بیایید تراکنش را در یک بلوک قرار دهیم استثناء تلاش. بنابراین، به احتمال زیاد، خطاها فقط در زمان نوشتن در دایرکتوری یا ثبت اطلاعات ممکن است رخ دهند آموزش مقدماتیآن را از معامله خارج کنید.

&OnServerWithoutContext Procedure ExecuteTransactionOnServer() //یک محصول جدید ایجاد کنیدمحصول = دایرکتوری ها محصولات. CreateElement(); تولید - محصول. نام = " سوراخ سوراخ " ; //یک رکورد با قیمت ایجاد کنیدمجموعه رکورد =RegistersInfo. قیمت. CreateRecordSet() ; NewRecord = مجموعه رکورد. اضافه کردن() ؛ ورودی جدید. Period = CurrentDate() ; ورودی جدید. مبلغ = 100 ; //تراکنش را در تلاشی انجام دهیدتلاش برای StartTransaction() ; تولید - محصول. نوشتن() ؛ ورودی جدید. محصول = محصول ارتباط دادن؛ RecordSet. نوشتن() ؛ CommitTransaction() ; Exception CancelTransaction(); Message = New MessageToUser; پیام. متن = ; پیام. برای گزارش () ; ورود به دفترچه ثبت ( "هنگام ثبت محصول و قیمت آن خطایی رخ داد") ؛ EndTry پایان رویه

چگونه انجام ندهیم

کسانی که تازه شروع به کار با تراکنش ها کرده اند، اغلب تمایل به انجام این کار را دارند

StartTransaction(); تلاش برای StartTransaction() ; //بلوک عملیات FixTransaction(); Exception CancelTransaction(); EndTry تلاش برای StartTransaction() ; //بلوک عملیات FixTransaction(); Exception CancelTransaction(); EndTry CommitTransaction() ;

یا در یک حلقه

StartTransaction(); برای هر داده از DataArray حلقه تلاش برای StartTransaction() ; داده ها. نوشتن() ؛ CommitTransaction() ; Exception CancelTransaction(); EndTry چرخه پایان ; CommitTransaction() ;

در نگاه اول، ما همه چیز را مطابق با توصیه های 1C انجام دادیم. اما واقعیت این است که پلت فرم 1C از تراکنش های تودرتو پشتیبانی نمی کند. یعنی از نظر فنی می تونی اینطوری بنویسی. اما در عین حال، همه تراکنش‌های تودرتو، تراکنش‌های جدیدی را تشکیل نمی‌دهند، بلکه به همان تراکنش سطح بالا اشاره دارند. بنابراین، اگر خطایی در یکی از تراکنش‌های تودرتو رخ دهد، تراکنش تودرتوی بعدی را نمی‌توان انجام داد. سیستم پیامی مانند: "خطاهایی قبلاً در این تراکنش رخ داده است!". بیایید این را با یک مثال نشان دهیم. فرض کنید تصمیم داریم دو محصول را ثبت کنیم که هر کدام در معامله خودش است. و بیایید این تراکنش ها را در تراکنش سوم تودرتو کنیم. در مرحله بعد، با استفاده از روش، به طور مصنوعی در اولین تراکنش خطا ایجاد می کنیم ThrowException:

&OnServerWithoutContextرویه ExecuteTransactionOnServer() StartTransaction(); تلاش برای StartTransaction() ; محصول = دایرکتوری ها محصولات. CreateElement(); تولید - محصول. نام = "جدول" ; تولید - محصول. نوشتن() ؛ ThrowException "خطای ورود محصول."; CommitTransaction() ; Exception CancelTransaction(); Message = New MessageToUser; پیام. Text = DescriptionErrors() تلاش برای شروع تراکنش() ; محصول = دایرکتوری ها محصولات. CreateElement(); تولید - محصول. نام = "صندلی" ; تولید - محصول. نوشتن() ؛ CommitTransaction() ; Exception CancelTransaction(); Message = New MessageToUser; پیام. متن = توضیحات خطا() ; پیام. برای گزارش () ; EndTry CommitTransaction() ; پایان رویه

در نتیجه این روش، موارد زیر را در پنجره پیام مشاهده خواهیم کرد:

(ExternalProcessing.TransactionsTrying.Form.Form.Form(20)): خطا در نوشتن مورد. (ExternalProcessing.TransactionInTry.Form.Form.Form(40)): خطا در فراخوانی روش زمینه (Write): خطاهایی قبلاً در این تراکنش رخ داده است!

بنابراین، سازماندهی تراکنش های تودرتو در 1C کاملاً بی معنی است.

گزینه های ممکن

حال به گزینه ای که محصول و قیمت آن را ثبت کرده ایم برمی گردیم. اگر در حین اجرای تراکنش خطا داشته باشیم، درک اینکه در چه نقطه ای رخ داده است - هنگام ثبت محصول یا هنگام ثبت قیمت، دشوار خواهد بود، زیرا هر دو در یک تلاش اتفاق می افتند. برای تعیین محل وقوع خطا، باید هر عملیات نوشتن را در تلاش خودش بپیچانیم و از تراکنش‌های تودرتو اجتناب کنیم. برای این کار یک متغیر بولی معرفی می کنیم امتناعو بسته به ارزش آن در پایان تمامی عملیات، تراکنش را متعهد یا لغو می کنیم.

&OnServerWithoutContext Procedure ExecuteTransactionOnServer() // شروع تراکنشرد = نادرست ; StartTransaction(); // تلاش برای نوشتن یک محصولمحصول = دایرکتوری ها را امتحان کنید. محصولات. CreateElement(); تولید - محصول. نام = " سوراخ سوراخ " ; تولید - محصول. نوشتن() ؛ استثنا رد = درست ; Message = New MessageToUser; پیام. متن = "خطا در نوشتن مورد"; پیام. برای گزارش () ; EndTry // تلاش برای نوشتن قیمت AttemptRecordset =RegistersInfo. قیمت. CreateRecordSet() ; NewRecord = RecordSet. اضافه کردن() ؛ ورودی جدید. Period = CurrentDate() ; ورودی جدید. محصول = محصول ارتباط دادن؛ ورودی جدید. مبلغ = 100 ; RecordSet. نوشتن() ؛ استثنا رد = درست ; Message = New MessageToUser; پیام. متن = "خطا در نوشتن قیمت"; پیام. برای گزارش () ; EndTry // تعهد یا لغو معاملهاگر NOT Failure سپس CommitTransaction() ; در غیر این صورت CancelTransaction(); EndIf پایان رویه

هنگامی که ما هر داده ای را تکرار می کنیم و در یک حلقه می نویسیم، می توانید همین کار را انجام دهید. در این صورت، می‌توانیم فهرستی از تمام داده‌های دارای خطا، در صورت وجود، دریافت کنیم.

در آماده سازی برای صدور گواهینامه 1C Expert، در آستانه دو موضوع بسیار مهم و جهانی - قفل ها، می خواهم چیزی را تجزیه و تحلیل کنم که بدون آن مفاهیم فوق غیرممکن است - یک تراکنش DBMS.

معامله- دنباله ای از اعمال به طور منطقی مرتبط و غیرقابل تقسیم. معامله می تواند به طور کامل انجام شود یا اصلاً انجام نشود. روش COMMIT برای انجام تراکنش در DBMS استفاده می شود.

یک مثال معمولی از تراکنش، انتقال است پولاز یک حساب به حساب دیگر:

  1. شروع معامله؛
  2. مقدار پول را در حساب شماره 123 بخوانید;
  3. موجودی حساب 123 را 100 روبل کاهش دهید.
  4. ذخیره موجودی حساب شماره 123;
  5. مقدار پول را در حساب شماره 321 بخوانید;
  6. افزایش تعادل 100 روبل؛
  7. مقدار جدیدی از وجوه را در حساب 321 بنویسید.
  8. معامله را انجام دهد

267 درس ویدیویی 1C را به صورت رایگان دریافت کنید:

همانطور که می بینیم، اگر معامله به طور کامل انجام نشود، منطقی نیست.

الزامات کلیدی (ACID) برای یک DBMS تراکنشی

یکی از متداول ترین مجموعه الزامات برای تراکنش ها و DBMS تراکنش ها مجموعه ACID (اتمی، سازگاری، جداسازی، دوام) است. اینها ویژگی هایی هستند که هر معامله باید داشته باشد:

  • اتمی بودن- هیچ معامله ای نباید تا حدی ثابت شود.
  • ثبات- سیستم قبل از شروع تراکنش در یک وضعیت ثابت است و باید پس از اتمام معامله در وضعیت ثابت باقی بماند.
  • انزوا- در طول اجرای یک معامله، معاملات موازی نباید بر نتیجه آن تأثیر بگذارد.
  • ماندگاری- در صورت خرابی، تغییرات ایجاد شده توسط یک تراکنش با موفقیت انجام شده باید پس از بازگشت سیستم به کار ذخیره شود.

معاملات در 1C

معاملات در 1C 8.3 و 8.2 هر دو به صورت خودکار ایجاد می شوند و توسط توسعه دهندگان شرح داده می شوند.

با استفاده از متد ()TransactionActive، می توانید از فعال بودن تراکنش مطلع شوید.

نمونه ای از تراکنش خودکار، پردازش ارسال یک سند، نوشتن یک عنصر فرهنگ لغت در پایگاه داده، نوشتن مجموعه ای از رکوردهای ثبت اطلاعات و غیره است.

عنوان جذاب ظاهر شد، اما به پایان رسید. فوراً باید بگویم که ما در مورد 1C صحبت خواهیم کرد. نام مستعار 1C عزیز، شما نمی دانید چگونه با تراکنش ها کار کنید و نمی دانید چه استثناهایی وجود دارد. من با نگاه کردن به مقدار زیادی کد 1C که در طبیعت وحشی شرکت های داخلی متولد شده است به این نتیجه رسیدم. AT تنظیمات معمولیاین به اندازه کافی خوب است، اما مقدار هولناکی از کد سفارشی از نقطه نظر پایگاه داده به طور ناکارآمد نوشته شده است. آیا تا به حال خطای "خطاهایی در این تراکنش رخ داده است" را دیده اید؟ اگر چنین است، پس عنوان مقاله برای شما صدق می کند. بیایید در زیر برش بفهمیم که تراکنش ها چیست و چگونه هنگام کار با 1C به درستی آنها را مدیریت کنیم.

چرا باید زنگ خطر را به صدا در آورید

برای شروع، بیایید بفهمیم که خطای "خطاها قبلاً در این تراکنش رخ داده است" چیست. این در واقع یک چیز بسیار ساده است: شما در حال تلاش برای کار با پایگاه داده در داخل یک تراکنش قبلی (لغو شده) هستید. به عنوان مثال، متد CancelTransaction در جایی فراخوانی شده است و شما در حال تلاش برای انجام آن هستید.


چرا این بد است؟ زیرا خطا داده شدهبه شما چیزی در مورد محل وقوع مشکل نمی گوید. هنگامی که یک اسکرین شات با چنین متنی از طرف کاربر پشتیبانی می شود و به خصوص برای کد سرور، که یک فرد با آن تعاملی کار نمی کند، است ... می خواستم یک "خطای بحرانی" بنویسم، اما فکر کردم این یک کلمه پرحرف است که دیگر کسی به آن توجه نمی کند .... این یک الاغ است. این یک خطای برنامه نویسی است. این یک شکست تصادفی نیست. این یک باگ است که باید فوراً برطرف شود. زیرا هنگامی که فرآیندهای سرور پس‌زمینه شما در شب فعال است و شرکت به سرعت شروع به از دست دادن پول می‌کند، «خطاها قبلاً در این تراکنش رخ داده‌اند» آخرین چیزی است که می‌خواهید در گزارش‌های تشخیصی ببینید.


البته این احتمال وجود دارد که گزارش فناوری سرور (شما آن را در زمان تولید فعال کرده اید، درست است؟) به نوعی به تشخیص مشکل کمک کند، اما در حال حاضر نمی توانم گزینه ای را بیخود فکر کنم - دقیقاً چگونه می توان واقعی را پیدا کرد. علت خطای مشخص شده در آن و تنها یک دلیل واقعی وجود دارد - برنامه نویس واسیا یک استثنا در داخل معامله دریافت کرد و تصمیم گرفت که یک بار - نه یک کاراباس "فکر کنید، این یک اشتباه است، بیایید ادامه دهیم."

معاملات در 1C چیست؟

نوشتن در مورد حقایق ابتدایی شرم آور است، اما، ظاهرا، کمی باید انجام شود. تراکنش ها در 1C مانند تراکنش های یک DBMS است. این تراکنش‌های خاص «1C» نیستند، این تراکنش‌ها در DBMS هستند. با توجه به ایده کلی تراکنش ها، می توان آنها را یا به طور کامل اجرا کرد یا اصلاً اجرا نکرد. تمام تغییرات جداول پایگاه داده در یک تراکنش را می توان به یکباره لغو کرد، گویی هیچ اتفاقی نیفتاده است.


علاوه بر این، باید بدانید که تراکنش‌های تودرتو در 1C پشتیبانی نمی‌شوند. در واقع، آنها "در 1C" پشتیبانی نمی شوند، اما اصلا پشتیبانی نمی شوند. حداقل، آن دسته از DBMS هایی که 1C با آنها قادر به کار است. برای مثال، تراکنش‌های تودرتو در MS SQL و Postgres در دسترس نیستند. هر تماس "تودرتو" به StartTransaction به سادگی شمارنده تراکنش را افزایش می دهد و هر تماس با "CommitTransaction" شمارنده را کاهش می دهد. این رفتار در کتاب ها و مقالات بسیاری شرح داده شده است، اما نتایج حاصل از این رفتار ظاهراً به اندازه کافی تحلیل نشده است. به طور دقیق، SQL دارای یک اصطلاح است SAVEPOINT، اما 1C از آنها استفاده نمی کند و این چیز کاملاً خاص است.



رویه بسیار مفید و مهم کد(فهرست مراجع مرجع) StartTransaction(); برای هر پیوند از لیست پیوندهای حلقه مرجع شیء مرجع = Reference.GetObject(); ReferenceObject.WhichField = "من از کد تغییر کرده ام"; DirectoryObject.Write(); چرخه پایان CommitTransaction(); پایان رویه

کد به زبان انگلیسی

نه واقعا. من مطلقاً نمی خواهم فقط به خاطر سرگرم کردن طرفداران هولیوارها و جنگ های مقدس، نمونه هایی را به زبان انگلیسی تکرار کنم.


مطمئناً شما در حال نوشتن چنین کدی هستید، درست است؟ مثال کد ارائه شده حاوی خطاهایی است. حداقل سه. میدونی چیه؟ اولین مورد را فوراً به شما می گویم، مربوط به قفل های شیء است و ارتباط مستقیمی با تراکنش ها ندارد. در مورد دوم - کمی بعد. خطای سوم یک بن بست است که هنگام اجرای این کد به صورت موازی رخ می دهد، اما این موضوع برای یک مقاله جداگانه است، ما اکنون آن را در نظر نمی گیریم تا کد را پیچیده نکنیم. کلمه کلیدیبرای گوگل: قفل های مدیریت شده بن بست.


توجه کنید، کد ساده است. این فقط یک ماشین در سیستم های 1C شماست. و شامل حداقل 3 خطا در یک زمان است. در اوقات فراغت خود فکر کنید چه تعداد خطا در سناریوهای پیچیده تر برای کار با تراکنش های نوشته شده توسط برنامه نویسان 1C شما وجود دارد :)

قفل اشیا

بنابراین، اولین اشتباه. در 1C، قفل های شی وجود دارد، به اصطلاح "خوشبینانه" و "بدبینانه". کسی که این اصطلاح را مطرح کرد، نمی‌دانم، می‌کشت :). کاملاً غیرممکن است که به یاد بیاوریم کدام یک مسئول چه چیزی است. به طور مفصل در مورد آنها و همچنین در سایر ادبیات IT همه منظوره نوشته شده است.


ماهیت مشکل این است که در مثال کد مشخص شده، شی پایگاه داده تغییر می کند، اما یک کاربر تعاملی (یا یک رشته پس زمینه همسایه) می تواند در جلسه دیگری بنشیند، که این شی را نیز تغییر می دهد. این جایی است که یکی از شما ممکن است با خطای "ورود تغییر یافته یا حذف شده" دریافت کند. اگر این اتفاق در یک جلسه تعاملی رخ دهد، کاربر سر خود را می خاراند، فحش می دهد و سعی می کند فرم را دوباره باز کند. اگر این اتفاق در یک رشته پس‌زمینه رخ دهد، باید آن را در گزارش‌ها جستجو کنید. و گزارش ثبت نام، همانطور که می دانید، کند است، و پشته ELK برای لاگ های 1C در صنعت ما توسط چند نفر راه اندازی شده است (به هر حال، ما از جمله کسانی هستیم که راه اندازی کرده و به دیگران کمک می کنیم تا راه اندازی شوند: ))


به طور خلاصه، این یک اشتباه آزاردهنده است و بهتر است آن را نداشته باشید. بنابراین، استانداردهای توسعه به وضوح بیان می کنند که قبل از تغییر اجسام، لازم است با استفاده از " قفل شی روی آنها قرار داده شود. ReferenceObject.Lock()سپس جلسه همزمان (که باید این کار را نیز انجام دهد) قادر به شروع عملیات تغییر نخواهد بود و شکست مورد انتظار و کنترل شده را دریافت خواهد کرد.

و اکنون در مورد معاملات

با رفع خطای اول، به سراغ خطای دوم می رویم.


اگر در این روش یک بررسی استثنا ارائه نکنید، یک استثنا (به عنوان مثال، به احتمال زیاد در روش "Record ()" شما را از این روش بدون تکمیل معامله. یک استثنا از روش "Write" می تواند به دلایل مختلفی ایجاد شود، به عنوان مثال، برخی از بررسی های برنامه در منطق تجاری کار می کنند، یا قفل شی که در بالا ذکر شد رخ می دهد. به هر حال، خطای دوم می گوید: کدی که تراکنش را شروع کرده است مسئولیتی در قبال تکمیل آن ندارد.



من این مشکل را اینگونه می نامم. در تحلیلگر کد استاتیک 1C ما بر اساس SonarQube، ما حتی چنین عیب‌یابی‌هایی را جداگانه ساخته‌ایم. اکنون دارم روی توسعه آن کار می کنم و فانتزی برنامه نویسان 1C که کد آنها برای تجزیه و تحلیل به من می رسد ، گاهی اوقات من را شوکه می کند و وحشت می کند ...


چرا؟ زیرا استثنایی که در 90 درصد موارد در داخل تراکنش ایجاد می شود، اجازه رفع این تراکنش را نمی دهد و منجر به خطا می شود. باید درک کرد که 1C به طور خودکار یک تراکنش ناقص را تنها پس از بازگشت از کد اسکریپت به سطح کد پلت فرم برمی گرداند. تا زمانی که در سطح کد 1C هستید، تراکنش فعال باقی می ماند.


بیایید یک سطح در پشته تماس بالا برویم:


رویه ImportantCode() LinkList = GetWhereToLinkList(); کد بسیار مفید و مهم (ReferenceList)؛ پایان رویه

ببین چه اتفاقی افتاده. روش مشکل ساز ما از جایی خارج، بالاتر از پشته فراخوانی می شود. در سطح این روش، توسعه دهنده هیچ ایده ای ندارد که آیا تراکنش هایی در روش Very UsefulAnd ImportantCode وجود خواهد داشت یا خیر. و اگر انجام دهند، آیا همه آنها تکمیل خواهند شد... ما همه برای صلح و محصور کردن اینجا هستیم، درست است؟ نویسنده روش "ImportantCode" نباید به این فکر کند که دقیقاً در داخل متدی که فراخوانی می کند چه اتفاقی می افتد. معامله ای که در آن تراکنش اشتباه پردازش شده است. در نتیجه، تلاش برای کار با پایگاه داده پس از پرتاب یک استثنا از داخل یک تراکنش، با احتمال زیاد، منجر به این واقعیت می شود که "در این تراکنش، بلاههههه ..."

لکه دار کردن تراکنش ها بین روش ها

قانون دوم کد "معامله امن": تعداد مرجع تراکنش در ابتدای روش و در پایان باید یک مقدار باشد. شما نمی توانید یک تراکنش را با یک روش شروع کنید و آن را به روشی دیگر خاتمه دهید. احتمالاً می‌توانید استثناهایی برای این قاعده پیدا کنید، اما این یک نوع کد سطح پایین است که توسط افراد شایسته‌تر نوشته می‌شود. در کل نمیشه اینجوری نوشت.


مثلا:


رویه ImportantCode() LinkList = GetWhereToLinkList(); کد بسیار مفید و مهم (ReferenceList)؛ CommitTransaction(); // بلیط جهنم، گفتگوی جدی با نویسنده درباره روابط سخت کاری ما. پایان رویه

موارد فوق کدهای غیرقابل قبول است. شما نمی توانید روش ها را به گونه ای بنویسید که تماس گیرنده تراکنش های احتمالی (یا احتمالی - چه کسی می داند) را در سایر روش هایی که فراخوانی می کند به خاطر بسپارد و پیگیری کند. این نقض کپسولاسیون و رشد کد اسپاگتی است که با حفظ سلامت عقل قابل ردیابی نیست.


به خصوص جالب است که به یاد داشته باشید که کد واقعی بسیار بزرگتر از نمونه های مصنوعی 3 خطی است. جستجو برای شروع و پایان تراکنش ها با شش سطح تودرتو - این به طور مستقیم انگیزه گفتگوهای صمیمانه با نویسندگان را فراهم می کند.

تلاش برای رفع کد

بیایید به روش اصلی برگردیم و سعی کنیم آن را برطرف کنیم. فوراً باید بگویم که ما هنوز قفل شی را تعمیر نمی کنیم، فقط برای اینکه کد مثال را پیچیده نکنیم.

اولین رویکرد یک نام مستعار معمولی 1C

معمولاً برنامه نویسان 1C می دانند که هنگام نوشتن می توان استثناء ایجاد کرد. آنها همچنین از استثناها می ترسند، بنابراین سعی می کنند همه آنها را بگیرند. به عنوان مثال، مانند این:


رویه بسیار مفید و مهم کد(فهرست مراجع مرجع) StartTransaction(); برای هر پیوند از لیست پیوندهای حلقه مرجع شیء مرجع = Reference.GetObject(); ReferenceObject.WhichField = "من از کد تغییر کرده ام"; تلاش برایReferenceObject.Write(); Exception Log.Error("نوشتن عنصر %1 ناموفق بود"، مرجع); ادامه پایان تلاش؛ چرخه پایان CommitTransaction(); پایان رویه

خوب، بهتر شد، درست است؟ در حال حاضر، اشتباهات احتمالیسوابق پردازش و حتی ثبت می شوند. در هنگام نوشتن یک شی دیگر استثناء وجود نخواهد داشت. و در گزارشی که حتی می توانید ببینید - روی کدام شی، او خیلی تنبل نبود، او پیوندی را در پیام به جای "خطای ورودی دایرکتوری" نشان داد، زیرا توسعه دهندگانی که همیشه عجله دارند اغلب دوست دارند بنویسند. به عبارت دیگر نگرانی برای کاربر و رشد شایستگی ها وجود دارد.


با این حال، یک نام مستعار با تجربه 1C در اینجا می گوید که نه، بهتر نشد. در واقع، هیچ چیز تغییر نکرده است، و شاید حتی بدتر. در روش "Write()" خود پلتفرم 1C یک تراکنش نوشتن را شروع می کند و این تراکنش قبلاً در رابطه با ما تودرتو خواهد بود. و اگر در زمان کار با پایگاه داده، 1C تراکنش خود را عقب نشینی کند (به عنوان مثال، یک استثنا منطق تجاری ایجاد می شود)، تراکنش سطح بالای ما همچنان به عنوان "فاسد" علامت گذاری می شود و امکان پذیر نخواهد بود. درستش کن در نتیجه، این کد مشکل ساز باقی می ماند و زمانی که می خواهید commit کنید، «خطاها قبلاً رخ داده است» را نمایش می دهد.


حال تصور کنید که ما در مورد یک روش کوچک صحبت نمی کنیم، بلکه در مورد یک پشته فراخوان عمیق صحبت می کنیم، جایی که در انتهای آن شخصی تراکنش آغاز شده را از متد خود گرفته و "آزاد" می کند. رویه‌های سطح بالا ممکن است هیچ ایده‌ای نداشته باشند که شخصی در آن پایین تراکنش‌ها را آغاز کرده است. در نتیجه، کل کد با یک خطای نامشخص از کار می افتد که بررسی اصولی آن غیرممکن است.


کدی که یک تراکنش را شروع می کند برای تکمیل یا بازگرداندن آن مورد نیاز است.صرف نظر از هر استثنا. هر مسیر کد باید بررسی شود تا ببینیم آیا روش بدون انجام یا لغو تراکنش خارج می شود یا خیر.

روش های کار با تراکنش ها در 1C

یادآوری این نکته اضافی نیست که به طور کلی 1C تراکنش هایی را برای ما فراهم می کند تا با آنها کار کنیم. اینها روش های شناخته شده ای هستند:

  • StartTransaction()
  • CommitTransaction()
  • CancelTransaction()
  • TransactionActive()

3 روش اول واضح است و آنچه را که به نام خود می گویند انجام دهید. اگر شمارنده تراکنش بزرگتر از صفر باشد، آخرین روش True را برمی گرداند.


و یک ویژگی جالب وجود دارد. اگر تعداد تراکنش صفر باشد، روش‌های خروج از تراکنش (تعهد و لغو) استثناهایی را ایجاد می‌کنند. یعنی اگر یکی از آنها را خارج از تراکنش فراخوانی کنید، خطایی رخ می دهد.


چگونه از این روش ها به درستی استفاده کنیم؟ خیلی ساده: باید قانون فرموله شده در بالا را بخوانید:


چگونه می توانید از این قانون پیروی کنید؟ بیایید تلاش کنیم:


در بالا قبلاً فهمیدیم که روش DoSomething بالقوه خطرناک است. می تواند نوعی استثنا ایجاد کند و تراکنش از روش ما خارج می شود. خوب، بیایید یک کنترل کننده استثنای احتمالی اضافه کنیم:


StartTransaction(); تلاش برای DoSomething(); استثنا // اینجا چه بنویسیم؟ پایان تلاش؛ CommitTransaction();

عالی است، ما خطای رخ داده را گرفتیم، اما با آن چه کنیم؟ پیامی به گزارش بنویسید؟ خوب، شاید اگر کد ثبت خطا دقیقاً در این سطح باشد و ما در اینجا منتظر خطا هستیم. و اگر نه؟ اگر در اینجا انتظار خطا نداشتیم؟ سپس ما فقط باید این استثنا را در بالا پاس کنیم، اجازه دهیم لایه دیگری از معماری به آنها بپردازد. این کار با عملگر "CauseException" بدون آرگومان انجام می شود. در این sipplus های جاوا شما، این کار دقیقاً به همان صورت با دستور throw انجام می شود.


StartTransaction(); تلاش برای DoSomething(); استثنا ThrowException; پایان تلاش؛ CommitTransaction();

بنابراین، صبر کنید... اگر ما فقط استثنا را بیشتر پرتاب می کنیم، پس چرا اصلاً یک Try وجود دارد؟ و دلیل آن این است: قانون ما را مجبور می کند از تکمیل معامله ای که شروع کرده ایم اطمینان حاصل کنیم.


StartTransaction(); تلاش برای DoSomething(); Exception CancelTransaction(); ThrowException; پایان تلاش؛ CommitTransaction();

حالا به نظر زیباست با این حال، ما به یاد داریم که به کد DoSomething() اعتماد نداریم. ناگهان، در داخل نویسنده آن این مقاله را نخواند، و نمی داند چگونه با معاملات کار کند؟ ناگهان او را به آنجا برد و روش CancelTransaction را صدا زد یا برعکس آن را درست کرد؟ این برای ما بسیار مهم است کنترل کننده استثنا استثنای جدیدی ایجاد نکرده است، در غیر این صورت خطای اصلی از بین می رود و بررسی مشکلات غیر ممکن می شود. و ما به یاد داریم که متدهای Commit و Cancel می توانند در صورت عدم وجود تراکنش استثنا ایجاد کنند. اینجاست که روش TransactionActive به کار می آید.

نسخه نهایی

در نهایت، می‌توانیم کد صحیح و «ایمن برای تراکنش» بنویسیم. او اینجا است:


**UPD: نظرات زمانی که CommitTransaction در داخل بلوک تلاش قرار دارد، گزینه ایمن‌تری را پیشنهاد می‌کند. این گزینه در اینجا نشان داده شده است، قبلاً Commit بعد از بلوک Attempt-Exception قرار داشت.


StartTransaction(); تلاش برای DoSomething(); CommitTransaction(); Exception If TransactionActive() then CancelTransaction(); EndIf ThrowException; پایان تلاش؛

صبر کنید، این فقط "لغو معامله" نیست که می تواند خطا ایجاد کند. پس چرا "CommitTransaction" در شرایط مشابه با "TransactionActive" قرار نمی گیرد؟ باز هم طبق همین قانون: کدی که تراکنش را شروع کرده است باید مسئول تکمیل آن باشد.تراکنش ما لزوماً اولین معامله نیست، بلکه می تواند تودرتو باشد. در سطح انتزاع خود، فقط باید به معامله خود اهمیت دهیم. بقیه نباید برای ما جالب باشند. آنها غریبه هستند، ما نباید در قبال آنها پاسخگو باشیم. دقیقاً نباید. برای اطلاع از سطح واقعی باجه تراکنش نباید تلاش کرد. این دوباره کپسولاسیون را می شکند و منجر به "لکه گیری" منطق مدیریت تراکنش می شود. ما فقط فعالیت را در کنترل کننده استثنا بررسی کردیم و فقط از کنترل کننده خود مطمئن شدیم استثنای جدیدی ایجاد نخواهد کرد که مورد قبلی را "پنهان" کند.

چک لیست بازسازی مجدد

بیایید به چند مورد از رایج ترین موقعیت هایی که نیاز به مداخله در کد دارند نگاه کنیم.


الگو:


StartTransaction(); کاری بکنید()؛ CommitTransaction();

آن را در یک ساختار "ایمن" با Retry، Keepalive و Throw استثنا بپیچید.


الگو:


اگر TransactionActive() نباشد، سپس StartTransaction() EndIf

تجزیه و تحلیل و بازسازی. نویسنده نمی دانست دارد چه می کند. شروع تراکنش های تودرتو ایمن است. شما نیازی به بررسی شرایط ندارید، فقط باید یک تراکنش تودرتو را شروع کنید. در زیر مدول، او احتمالا هنوز آنجا را با تثبیت آنها منحرف می کند. این هموروئید تضمین شده است.


گزینه تقریبا مشابه:


اگر TransactionActive() سپس CommitTransaction() EndIf

به همین ترتیب: ارتکاب معامله به شرط عجیب است. چرا شرط دارد؟ چه، شخص دیگری قبلاً می توانست این معامله را انجام داده باشد؟ دلیل دعوا.


الگو:


StartTransaction() while Selection.Next() Loop // خواندن شی با مرجع // نوشتن شی EndCycle; CommitTransaction();
  1. قفل مدیریت شده را برای جلوگیری از بن بست معرفی کنید
  2. روش فراخوانی Block را وارد کنید
  3. همانطور که در بالا نشان داده شده است، در "امتحان" بپیچید

الگو:


StartTransaction() while Selection.Next() Loop Attempt Object.Write(); گزارش استثنا ("نوشتن ناموفق")؛ پایان تلاش؛ چرخه پایان CommitTransaction();

در صورت وجود استثنا، این تراکنش دیگر تکمیل نخواهد شد. ادامه چرخه فایده ای ندارد. کد باید با اشاره به کار اصلی بازنویسی شود. در صورت تمایل پیام خطای آموزنده تری ارائه دهید.

سرانجام

همانطور که احتمالاً قبلاً حدس زده اید، من متعلق به افرادی هستم که عاشق پلتفرم 1C و توسعه روی آن هستند. البته شکایاتی در مورد این پلتفرم به خصوص در محیط هایلود وجود دارد، اما به طور کلی به شما امکان می دهد تا به سرعت و کم هزینه برنامه های شرکتی بسیار با کیفیت را توسعه دهید. ارائه خارج از جعبه و ORM، و رابط کاربری گرافیکی، و رابط وب، و گزارش، و خیلی بیشتر. در نظرات Habré، آنها معمولاً هر چیزی متکبرانه می نویسند، و بنابراین، بچه ها، مشکل اصلی 1C، به عنوان اکوسیستم، یک پلت فرم یا یک فروشنده نیست. این یک آستانه ورود بسیار پایین است، که به افرادی که نمی دانند رایانه، پایگاه داده، سرویس گیرنده-سرور، شبکه و همه چیزهایی که وجود دارد، اجازه می دهد وارد صنعت شوند. 1C توسعه اپلیکیشن سازمانی را بسیار آسان کرده است. در 20 دقیقه می توانم یک سیستم حسابداری برای خرید و فروش با گزارش های انعطاف پذیر و یک مشتری وب روی آن بنویسم. پس از آن، برای من آسان است که در مورد خودم فکر کنم که در مقیاس بزرگ شما می توانید تقریباً به همان شکل بنویسید. به نوعی، 1C همه چیز را در درون خود انجام می دهد، نمی دانم چگونه، اما احتمالا این کار را انجام خواهد داد. من می نویسم "شروع معامله ()" ....

افزودن برچسب