1s 8 transakcií externých zdrojov. Jednorazoví klienti. Segmentácia na získanie opakovaných nákupov. Cena tovaru v objednávke

Bez ohľadu na zvolenú možnosť operácie (súbor alebo klient-server), 1C:Enterprise poskytuje prácu s informáciami uloženými v databáze pomocou transakčného mechanizmu.

transakcie- ide o nedeliteľný sled operácií manipulácie s údajmi z hľadiska vplyvu na databázu. Je to všetko alebo nič a prenesie databázu z jedného konzistentného stavu do iného konzistentného stavu. Ak z nejakého dôvodu zlyhá jedna z akcií transakcie alebo dôjde k nejakej poruche systému, databáza sa vráti do stavu, ktorý bol pred začiatkom transakcie (transakcia sa vráti späť).

Systém 1C:Enterprise implicitne volá transakcie pri vykonávaní akýchkoľvek akcií súvisiacich s úpravou informácií uložených v databáze. V transakcii sa napríklad volajú všetky obslužné rutiny udalostí umiestnené v moduloch objektov a sady záznamov, ktoré súvisia s modifikáciou údajov databázy. Transakcia tiež číta objekty nasledujúcich typov: Výmena PlanObject, DocumentObject, DictionaryObject, Plan of Types of CharacteristicsObject, Plan of Types of CalculationObject, Chart Of AccountsObject, BusinessProcessObject, TaskObject, SequenceRecordSet,RegisterInformationRecordSet,AkumuláciaRegisterRecordSet,RegisterRegisterRecordRecord. Zároveň je v režime spravovaných zámkov nastavený zdieľaný zámok na hodnotu registrátora pre sady záznamov a na hodnoty filtra pre sadu záznamov nezávislého informačného registra.

Spolu s tým môže vývojár použiť prácu s transakciami v explicitnej forme. Na tento účel sa používajú postupy globálneho kontextu. StartTransaction(), CommitTransaction() a CancelTransaction().

Použitie explicitného vyvolania transakcie

Metóda StartTransaction() umožňuje otvoriť transakciu. Potom môžu byť všetky zmeny databázových informácií vykonané nasledujúcimi príkazmi buď akceptované ako celok, alebo zamietnuté ako celok. Ak chcete prijať všetky vykonané zmeny, použite metódu CommitTransaction(). Ak chcete vrátiť späť všetky zmeny vykonané v otvorenej transakcii, použite metódu CancelTransaction(). Ak počet volaní metódy StartTransaction() presahuje počet volaní metódy CommitTransaction() alebo CancelTransaction(), potom systém vykoná implicitné volanie metódy CancelTransaction() v nasledujúcich prípadoch:

● na konci vykonávania vstavaného jazyka (obslužný program udalostí, externé pripojenie, automatizačný server);

● pri prenose riadenia zo servera na klienta.

Ak počet volaní metódy CommitTransaction() alebo CancelTransaction() presahuje počet volaní metódy StartTransaction(), potom keď sa uskutoční ďalšie volanie metódy CommitTransaction() alebo CancelTransaction() bude vyhodená výnimka. Schéma práce s transakciou vo všeobecnosti teda môže vyzerať takto:

Pokus

StartTransaction();

// Postupnosť príkazov

CommitTransaction();

Výnimka

CancelTransaction();

Koniec pokusu;

Pri používaní tejto schémy je potrebné mať na pamäti, že nie všetky chyby, ktoré sa vyskytnú pri práci s databázou, systém spracuje rovnakým spôsobom. Vo všeobecnosti možno všetky chyby databázy rozdeliť do dvoch kategórií:

● neobnoviteľné,

● obnoviteľné.

Neopraviteľné chyby sú chyby, ktoré môžu narušiť normálne fungovanie systému 1C:Enterprise, napríklad môžu byť poškodené dáta. Ak sa vyskytne neodstrániteľná chyba, vykonávanie systému 1C:Enterprise sa v každom prípade ukončí. Ak sa počas vykonávania transakcie vyskytne neodstrániteľná chyba, potom všetky zmeny vykonané v rámci tejto transakcie systém zruší.

Opraviteľné chyby sú chyby, ktoré nespôsobujú vážne poruchy v prevádzke systému 1C:Enterprise. V prípade odstrániteľnej chyby je možné pokračovať v ďalšej prevádzke systému. V tomto prípade sa samozrejme zastaví samotná operácia, ktorá chybu spôsobila a vyhodí sa výnimka, ktorú môže konštrukcia zachytiť a spracovať

Pokus... Výnimka... Koniec pokusu.

Vnorené volanie transakcie

V rámci už prebiehajúcej transakcie máte prístup k procedúram StartTransaction(), CommitTransaction() a CancelTransaction(). Môže sa použiť napríklad nasledujúci vzor hovoru:

StartTransaction();

StartTransaction();

CommitTransaction();

// Vnorené volanie transakcie

StartTransaction();

CommitTransaction();

CommitTransaction();

Takáto výzva však neznamená spustenie novej transakcie v rámci už prebiehajúcej.

POZOR!1C:Enterprise nepodporuje vnorené transakcie.To znamená, že iba transakcia špičková úroveň.

Všetky transakcie volané v rámci už otvorenej transakcie v skutočnosti patria do tej istej transakcie a netvoria vnorenú transakciu. Zrušenie zmien vykonaných vo vnorenej transakcii teda v konečnom dôsledku nebude mať za následok zrušenie zmien v samotnej vnorenej transakcii, ale zrušenie všetkých zmien v transakcii najvyššej úrovne. Súčasne sa ignorujú príkazy vykonané vo vnorenej transakcii.

Vplyv transakcií na fungovanie programových objektov

Vo všeobecnosti sú softvérové ​​objekty používané 1C:Enterprise absolútne „transparentné“ pre databázové transakcie. Inými slovami, databázové transakcie možno volať pri vykonávaní rôzne metódy programové objekty, avšak napríklad akcie vykonané databázou, keď je transakcia vrátená späť, vo všeobecnosti neovplyvňujú zodpovedajúce softvér predmety.

Z toho vyplýva, že pri zrušení databázových transakcií musí vývojár (ak je to potrebné) samostatne zabezpečiť adekvátnu zmenu údajov príslušných program predmety. Dá sa to urobiť opätovným načítaním všetkých údajov objektu alebo zmenou niektorých atribútov objektu programu.

Z tohto pravidla existujú výnimky. Vzhľadom na významné aplikačné špecifiká objektov programu 1C:Enterprise môže v niektorých prípadoch vrátenie zmien vykonaných v databáze stále ovplyvniť hodnoty vlastností príslušných program predmety. Stáva sa to v nasledujúcich prípadoch:

● keď je transakcia zrušená, príznak účtovania dokladu obnoví hodnotu, ktorú mal pred začiatkom transakcie;

● ak bol objekt vytvorený a zapísaný v transakcii, potom sa referenčná hodnota vymaže, keď sa transakcia vráti späť;

● ak bol objekt vytvorený mimo transakcie a pri zápise do transakcie bol použitý automaticky vygenerovaný kód/číslo, pri zrušení transakcie sa kód/číslo vymaže.

2017-08-12

Vytvorte vlastné transakcie na údržbu objektov OM.

Úvod

Myslím si, že mnohí funkční konzultanti SAP sa stretli s transakciou údržby objektov riadenia organizácie. Totiž transakcia PP01

Použitie tejto transakcie umožňuje užívateľovi spravovať infotypy organizačného manažmentu pre tie typy objektov, ktoré sa používajú v automatizovaných obchodných procesoch. Veľmi často sa táto transakcia používa ako jediný vstupný bod pre prácu so všetkými typmi objektov riadenia organizácie, čo v skutočnosti nie je veľmi dobrý postup. No, alebo nie veľmi pohodlné. Aj keď určite bežné. Ďalej sa vám pokúsim povedať, aká by mohla byť alternatíva.

Tabuľka T77S0, skupina "TCODE"

Pri konfigurácii objektov OM sa s najväčšou pravdepodobnosťou dotknete nastavenia umiestneného na nasledujúcej ceste SPRO:

IMG: Personálny manažment -> Organizačný manažment -> Základné nastavenia -> Vylepšenie dátového modelu -> Údržba typov objektov

Tu vytvárate nové OM objekty, dávate im mená, vyberáte ikony a definujete pre ne nejaké nastavenia... Momentálne nás zaujíma uzol " Kľúč typu objektu + transakcia"

Pred vami sa otvorí časť zobrazenia nastavenia. T77S0 s filtrovanými skupinovými hodnotami

Stojí za to venovať pozornosť skupine TCODE v ktorej, ak sa dobre pozriete, nájdete technické názvy transakcií, s ktorými ste s najväčšou pravdepodobnosťou museli pracovať. Navyše v kolóne hodnotušpecifikuje sa typ objektu, pre ktorý je tá alebo oná transakcia určená.

Čo je na týchto transakciách zvláštne?

Pri použití transakcií, ktoré sú určené na udržiavanie špecifického typu objektu, nemusíte vyberať práve tieto typy objektov, ktoré sú štandardne dostupné v transakcii. PP01. Teda spustením napríklad transakcie PO09, okamžite začnete pracovať s objektmi typu L

Vytvorenie novej transakcie pre váš vlastný objekt riadenia organizácie

V jednej z mojich predchádzajúcich poznámok som hovoril o tom, ako môžete vytvoriť nový objekt OM + pridať k nemu vyhľadávanie štruktúry

Od tohto materiálu nebudem ďaleko. Ako ukážku vytvorím novú transakciu na údržbu objektu 91.

Definovanie nového typu objektu v T77S0

V zobrazení nastavenia definujte názov budúcej transakcie T77S0

Hodnota „ZP91M“ je v tomto prípade názvom budúcej transakcie údržby objektu 91 . Uložte zmeny.

Vytvorenie novej transakcie na údržbu objektu OM

S transakciou SE93 vytvorte transakciu na údržbu vášho objektu. Nižšie je uvedený videoklip so sekvenciou akcií, ktoré je potrebné vykonať na vytvorenie príslušnej transakcie

Venujte pozornosť hodnotám, ktoré boli použité pre polia program, číslo obrazovky,Autorizačný objekt. Teraz začnite novú transakciu

Používateľ má možnosť pracovať iba s určitým typom objektu, ktorý sa v určitom zmysle dá nazvať pohodlím, a ak chcete, minimalizáciou ďalších akcií na výber požadovaného objektu.

Naposledy sme recenzovali najjednoduchší spôsob pomocou vstavaného jazyka 1C. Na praxi transakcií oveľa častejšie sa používa v spojení s dizajnom. To umožňuje v prípade chyby pokračovať vo vykonávaní kódu, ako aj vydať príslušné chybové hlásenie používateľovi a zapísať informácie do denníka alebo súboru denníka na ďalšiu analýzu správcom systému.

Ak sa pozrieme na technickú dokumentáciu alebo na disk ITS, uvidíme, že 1C odporúča nasledujúci spôsob organizácie transakcie pri pokuse

Pokus //jeden. Začiatok transakcie. StartTransaction() ; //2. Blok operácií, ktoré sa vykonávajú v transakcii. //3. Ak sú všetky operácie úspešné, potvrďte transakciu. CommitTransaction() ; Výnimka //štyri. Ak sa pri vykonávaní kódu vyskytnú chyby, transakciu zrušíme. CancelTransaction() ; //5. V prípade potreby napíšte do logu. //6. V prípade potreby zobrazte používateľovi správu. EndTry ;

V skutočnosti kód nevyžaduje žiadne špeciálne vysvetlenia. Ak je v procese pokusov vykonania transakčného kódu, dôjde k chybe, okamžite spadneme do bloku výnimkou, t.j. pred metódou CommitTransaction() jednoducho sa tam nedostaneme. No a vo výnimke transakciu zodpovedajúcim spôsobom zrušíme a v prípade potreby zobrazíme chybové hlásenie a zapíšeme informácie do logu. Je veľmi žiaduce opraviť chyby v protokole, najmä pri operáciách, ktoré sa vykonávajú bez zásahu používateľa (napríklad plánované úlohy). To umožní ďalšiu analýzu chyby. Namiesto zapisovania do logu si môžete dohodnúť zasielanie správ administrátorovi e-mailom.

Teraz, vyzbrojení novými poznatkami, skúsme upraviť kód, o ktorom sa hovorí v článku o . Pripomínam, že sme zvažovali záznam v adresári Produkty a v informačnom registri cena podľa nasledujúcej schémy:

&OnServerWithoutContext StartTransaction() ; //napísať novú položku Produkt = Adresáre. Produkty. CreateElement() ; Produkt. Názov = "Hole Punch" ; Produkt. Napíšte() ; //napíš cenu Recordset = RegistreInfo. Cena. CreateRecordset() ; NewRecord = Sada záznamov. Add() ; Nový vstup. Obdobie = CurrentDate() ; Nový vstup. Produkt = Produkt. Link; Nový vstup. Suma = 100 ; RecordSet. Napíšte() ; CommitTransaction() ; EndProcedure

Teraz dajme transakciu do bloku Pokus o výnimku. S najväčšou pravdepodobnosťou sa chyby môžu vyskytnúť iba v čase zápisu do adresára alebo do informačného registra predbežné školenie vyňať ho z transakcie.

&OnServerWithoutContext Postup ExecuteTransactionOnServer() //vytvorte nový produkt Produkt = Adresáre. Produkty. CreateElement() ; Produkt. Názov = "Hole Punch" ; //Vytvorte záznam s cenou Recordset = RegistreInfo. Cena. CreateRecordSet() ; NewRecord = Sada záznamov. Add() ; Nový vstup. Obdobie = CurrentDate() ; Nový vstup. Suma = 100 ; //Pokúste sa vykonať transakciu Pokus o spustenie transakcie() ; Produkt. Napíšte() ; Nový vstup. Produkt = Produkt. Link; RecordSet. Napíšte() ; CommitTransaction() ; Výnimka CancelTransaction() ; Správa = New MessageToUser; Správa. Text = ; Správa. Ohlásiť() ; Záznam v denníku( "Pri zaznamenávaní produktu a jeho ceny sa vyskytla chyba"); EndTry ; EndProcedure

AKO NEROBIŤ

Tí, ktorí práve začínajú pracovať s transakciami, majú často túžbu robiť to týmto spôsobom

StartTransaction() ; Pokus o spustenie transakcie() ; //Blok operácií FixTransaction() ; Výnimka CancelTransaction() ; EndTry ; Pokus o spustenie transakcie() ; //Blok operácií FixTransaction() ; Výnimka CancelTransaction() ; EndTry ; CommitTransaction() ;

Alebo v slučke

StartTransaction() ; Pre každý údaj zo slučky DataArray pokus o spustenie transakcie() ; Údaje. Napíšte() ; CommitTransaction() ; Výnimka CancelTransaction() ; EndTry ; EndCycle ; CommitTransaction() ;

Na prvý pohľad sme urobili všetko v súlade s odporúčaniami 1C. Faktom však je, že platforma 1C nepodporuje vnorené transakcie. To znamená, že technicky môžete písať takto. Zároveň však všetky vnorené transakcie nevytvárajú nové, ale odkazujú na rovnakú transakciu najvyššej úrovne. Ak sa teda vyskytne chyba v jednej z vnorených transakcií, ďalšia vnorená transakcia nemôže byť potvrdená. Systém zobrazí správu ako: "V tejto transakcii sa už vyskytli chyby!". Ukážme si to na príklade. Povedzme, že sa rozhodneme zaznamenať dva produkty, každý vo svojej vlastnej transakcii. A urobme tieto transakcie vnorené do tretej. Ďalej pomocou metódy umelo spôsobíme chybu v prvej transakcii ThrowException:

&OnServerWithoutContext Procedure ExecuteTransactionOnServer() StartTransaction() ; Pokus o spustenie transakcie() ; Produkt = Adresáre. Produkty. CreateElement() ; Produkt. Meno = "Tabuľka" ; Produkt. Napíšte() ; ThrowException "Chyba pri zadávaní produktu."; CommitTransaction() ; Výnimka CancelTransaction() ; Správa = New MessageToUser; Správa. Text = DescriptionErrors() Pokus o spustenie transakcie() ; Produkt = Adresáre. Produkty. CreateElement() ; Produkt. Meno = "Predseda" ; Produkt. Napíšte() ; CommitTransaction() ; Výnimka CancelTransaction() ; Správa = New MessageToUser; Správa. Text = DescriptionError() ; Správa. Ohlásiť() ; EndTry ; CommitTransaction() ; EndProcedure

V dôsledku tohto postupu uvidíme v okne správy nasledovné:

(ExternalProcessing.TransactionsTrying.Form.Form.Form(20)): Chyba pri zápise položky. (ExternalProcessing.TransactionInTransactionInTry.Form.Form.Form(40)): Chyba pri volaní kontextovej metódy (Write): V tejto transakcii sa už vyskytli chyby!

Organizácia vnorených transakcií v 1C je teda absolútne nezmyselná.

Možné možnosti

Teraz sa vráťme k možnosti, kde sme zaznamenali produkt a cenu zaň. Ak dôjde k chybe pri vykonávaní transakcie, bude ťažké pochopiť, v akom bode k nej došlo - pri zaznamenávaní produktu alebo pri zaznamenávaní ceny, pretože obe sa vyskytujú v rámci toho istého pokusu. Aby sme určili, kde nastala chyba, musíme zabaliť každú operáciu zápisu do jej vlastného pokusu a vyhnúť sa vnoreným transakciám. Aby sme to dosiahli, zavedieme booleovskú premennú odmietnutie a v závislosti od jej hodnoty na konci všetkých operácií transakciu potvrdíme alebo zrušíme.

&OnServerWithoutContext Postup ExecuteTransactionOnServer() // Spustenie transakcie Odmietnuť = Nepravda ; StartTransaction() ; // Pokúšam sa napísať produkt Vyskúšajte Produkt = Adresáre. Produkty. CreateElement() ; Produkt. Názov = "Hole Punch" ; Produkt. Napíšte() ; Odmietnutie výnimky = Pravda ; Správa = New MessageToUser; Správa. Text = "Chyba pri písaní položky"; Správa. Ohlásiť() ; EndTry ; // Pokúšam sa zapísať cenu AttemptRecordset =Informácie o registroch. Cena. CreateRecordSet() ; NewRecord = RecordSet. Add() ; Nový vstup. Obdobie = CurrentDate() ; Nový vstup. Produkt = Produkt. Link; Nový vstup. Suma = 100 ; RecordSet. Napíšte() ; Odmietnutie výnimky = Pravda ; Správa = New MessageToUser; Správa. Text = "Chyba pri písaní ceny"; Správa. Ohlásiť() ; EndTry ; // Potvrdenie alebo zrušenie transakcie Ak NIE JE Zlyhanie, potom CommitTransaction() ; Else CancelTransaction() ; Koniec Ak ; EndProcedure

Môžete urobiť to isté, keď iterujeme a zapisujeme akékoľvek údaje do slučky. V tomto prípade môžeme získať zoznam všetkých údajov s chybami, ak nejaké existujú.

V rámci prípravy na certifikáciu 1C Expert, v predvečer dvoch veľmi dôležitých a globálnych tém - zámkov, by som rád analyzoval niečo, bez čoho sú vyššie uvedené koncepty nemožné - transakciu DBMS.

transakcie- logicky spojený, nedeliteľný sled úkonov. Transakcia môže byť dokončená buď celá, alebo sa nemusí dokončiť vôbec. Metóda COMMIT sa používa na potvrdenie transakcie v DBMS.

Typickým príkladom transakcie je prevod Peniaze z jedného účtu na druhý:

  1. začať transakciu;
  2. prečítajte si sumu peňazí na účte číslo 123;
  3. znížiť zostatok na účte 123 o 100 rubľov;
  4. uložiť zostatok účtu číslo 123;
  5. prečítajte si sumu peňazí na účte číslo 321;
  6. zvýšiť zostatok o 100 rubľov;
  7. zapísať novú sumu peňažných prostriedkov na účet 321;
  8. vykonať transakciu.

Získajte 267 1C video lekcií zadarmo:

Ako vidíme, ak transakcia nie je dokončená úplne, potom to nemá zmysel.

Kľúčové požiadavky (ACID) pre transakčný DBMS

Jedným z najbežnejších súborov požiadaviek na transakcie a transakčné DBMS je súbor ACID (Atomicity, Consistency, Isolation, Durability). Toto sú vlastnosti, ktoré by mala mať každá transakcia:

  • Atomicita- žiadna transakcia by nemala byť čiastočne stanovená;
  • Dôslednosť- systém je v konzistentnom stave pred začiatkom transakcie a musí zostať v konzistentnom stave aj po dokončení transakcie;
  • Izolácia- počas vykonávania transakcie by paralelné transakcie nemali ovplyvniť jej výsledok;
  • Trvanlivosť- v prípade zlyhania by zmeny vykonané úspešne vykonanou transakciou mali zostať uložené po opätovnom spustení systému.

Transakcie v 1C

Transakcie v 1C 8.3 a 8.2 sa vytvárajú automaticky a sú opísané vývojármi.

Pomocou metódy TransactionActive() môžete zistiť, či je transakcia aktívna.

Príkladom automatickej transakcie je spracovanie zaúčtovania dokladu, zápis prvku slovníka do databázy, zápis súboru záznamov registra informácií atď.

Názov vyšiel chytľavo, ale prevaril. Hneď musím povedať, že budeme hovoriť o 1C. Milé prezývky 1C, neviete ako pracovať s transakciami a nerozumiete, aké sú výnimky. K tomuto záveru som dospel pri pohľade na veľké množstvo kódu 1C, ktorý sa narodil v divočine domáceho podniku. AT typické konfigurácie to je dosť v poriadku, ale strašné množstvo vlastného kódu je napísané nekompetentne z hľadiska databázy. Videli ste niekedy chybu „V tejto transakcii sa už vyskytli chyby“? Ak áno, názov článku sa vás týka. Poďme konečne zistiť, čo sú transakcie a ako ich správne zvládnuť pri práci s 1C.

Prečo potrebujete biť na poplach

Na začiatok si poďme zistiť, aká je chyba „V tejto transakcii sa už vyskytli chyby“. Toto je v skutočnosti veľmi jednoduchá vec: pokúšate sa pracovať s databázou v rámci už odvolanej (zrušenej) transakcie. Niekde bola napríklad volaná metóda CancelTransaction a vy sa ju pokúšate spáchať.


Prečo je to zlé? pretože daná chyba nehovorí nič o tom, kde sa problém skutočne stal. Keď screenshot s takýmto textom príde na podporu od užívateľa a hlavne pre kód servera, s ktorým človek interaktívne nepracuje, je ... chcel som napísať "kritickú chybu", ale myslel som si, že toto je buzzword, ktorému už nikto nevenuje pozornosť .... Toto je zadok. Toto je chyba programovania. Nejde o náhodné zlyhanie. Toto je chyba, ktorú je potrebné okamžite opraviť. Pretože keď sú vaše procesy servera na pozadí v noci zapnuté a spoločnosť začne rýchlo strácať peniaze, potom „V tejto transakcii sa už vyskytli chyby“ je posledná vec, ktorú chcete vidieť v diagnostických protokoloch.


Samozrejme, existuje možnosť, že technologický denník servera (máte to zapnutý vo výrobe, však?) nejakým spôsobom pomôže diagnostikovať problém, ale momentálne ma nenapadá žiadna možnosť - ako presne nájsť skutočný príčinu uvedenej chyby v ňom. A existuje len jeden skutočný dôvod - programátor Vasya dostal v rámci transakcie výnimku a rozhodol sa, že raz - nie karabas "mysli, je to chyba, poďme ďalej."

Čo sú transakcie v 1C

Je trápne písať o elementárnych pravdách, ale zrejme sa bude musieť urobiť trochu. Transakcie v 1C sú rovnaké ako transakcie v DBMS. Toto nie sú nejaké špeciálne transakcie „1C“, sú to transakcie v DBMS. Podľa všeobecnej myšlienky transakcií môžu byť vykonané buď úplne, alebo nemusia byť vykonané vôbec. Všetky zmeny databázových tabuliek vykonané v rámci transakcie je možné vrátiť naraz, ako keby sa nič nestalo.


Ďalej musíte pochopiť, že vnorené transakcie nie sú podporované v 1C. V skutočnosti nie sú podporované nie "v 1C", ale nie sú podporované vôbec. Aspoň tie DBMS, s ktorými je 1C schopný pracovať. Vnorené transakcie napríklad nie sú dostupné v MS SQL a Postgres. Každé „vnorené“ volanie StartTransaction jednoducho zvyšuje počítadlo transakcií a každé volanie „CommitTransaction“ znižuje počítadlo. Toto správanie je opísané v mnohých knihách a článkoch, ale závery z tohto správania zjavne neboli dostatočne analyzované. Prísne vzaté, SQL má tzv SAVEPOINT, ale 1C ich nepoužíva a táto vec je dosť špecifická.



Postup veľmi užitočný&dôležitýKód(Zoznam referencií) StartTransaction(); Pre každý odkaz zo zoznamu odkazov referenčnej slučky Referenčný objekt = Reference.GetObject(); ReferenceObject.WhichField = "Zmenil som sa z kódu"; DirectoryObject.Write(); EndCycle; CommitTransaction(); EndProcedure

Kód v angličtine

Nie naozaj. Absolútne nechcem duplikovať príklady v angličtine len kvôli zábavným fanúšikom holivarov a svätých vojen.


Určite píšete takýto kód, však? Uvedený príklad kódu obsahuje chyby. Aspoň tri. Vieš čo? O prvom vám poviem hneď, súvisí so zámkami objektov a nemá nič spoločné priamo s transakciami. O druhom - o niečo neskôr. Treťou chybou je uviaznutie, ku ktorému dôjde pri paralelnom vykonávaní tohto kódu, ale toto je téma na samostatný článok, teraz sa ním nebudeme zaoberať, aby sme kód nekomplikovali. Kľúčové slovo pre googlenie: zámky riadené uviaznutím.


Pozor, kód je jednoduchý. Toto je len auto vo vašich systémoch 1C. A obsahuje aspoň 3 chyby naraz. Vo svojom voľnom čase si premyslite, koľko chýb je v zložitejších scenároch práce s transakciami napísanými vašimi programátormi 1C :)

Objektové zámky

Takže prvá chyba. V 1C sú objektové zámky, takzvané „optimistické“ a „pesimistické“. Kto vymyslel termín, neviem, zabíjal by :). Je úplne nemožné spomenúť si, kto je za čo zodpovedný. Podrobne sa o nich píše, ako aj v inej všeobecnej IT literatúre.


Podstatou problému je, že v špecifikovanom príklade kódu sa objekt databázy zmení, ale interaktívny používateľ (alebo susedné vlákno na pozadí) môže sedieť v inej relácii, ktorá tiež zmení tento objekt. Tu sa môže jednému z vás zobraziť chyba „Položka bola upravená alebo vymazaná“. Ak sa to stane v interaktívnej relácii, používateľ sa poškriabe na hlave, bude nadávať a pokúsi sa znova otvoriť formulár. Ak sa to stane vo vlákne na pozadí, budete to musieť hľadať v protokoloch. A registračný denník, ako viete, je pomalý a zásobník ELK pre denníky 1C v našom odvetví nastavuje niekoľko ... (mimochodom, patríme k tým, ktorí nastavujú a pomáhajú ostatným s nastavením: ))


To je skrátka nepríjemná chyba a je lepšie ju nemať. Preto vývojové štandardy jasne stanovujú, že pred zmenou objektov je potrebné na ne umiestniť objektový zámok pomocou " ReferenceObject.Lock() Potom súbežná relácia (ktorá by to mala tiež robiť) nebude schopná spustiť operáciu zmeny a zaznamená očakávané, kontrolované zlyhanie.

A teraz o transakciách

Po vyriešení prvej chyby prejdime k druhej.


Ak v tejto metóde nezadáte kontrolu výnimky, výnimka (napríklad veľmi pravdepodobne v metóde „Záznam ()“ vás vyhodí z túto metódu bez dokončenia transakcie. Výnimka z metódy "Write" môže byť vyvolaná z rôznych dôvodov, napríklad budú fungovať niektoré kontroly aplikácií v obchodnej logike alebo dôjde k vyššie uvedenému uzamknutiu objektu. Každopádne, druhá chyba znie: kód, ktorý spustil transakciu, nezodpovedá za jej dokončenie.



Tak by som nazval tento problém. V našom analyzátore statického kódu 1C založenom na SonarQube sme takúto diagnostiku dokonca zabudovali samostatne. Teraz pracujem na jeho vývoji a fantázia programátorov 1C, ktorých kód ku mne prichádza na analýzu, ma niekedy šokuje a ohromí ...


prečo? Pretože výnimka vyvolaná vnútri transakcie v 90% prípadov neumožní túto transakciu opraviť a povedie k chybe. Malo by byť zrejmé, že 1C automaticky vráti nedokončenú transakciu až po návrate z kódu skriptu na úroveň kódu platformy. Pokiaľ ste na úrovni kódu 1C, transakcia zostáva aktívna.


Poďme o úroveň vyššie v zásobníku hovorov:


Procedure ImportantCode() LinkList = GetWhereToLinkList(); Veľmi užitočný&DôležitýKód(Zoznam referencií); EndProcedure

Pozrite sa, čo sa stane. Naša problematická metóda sa volá odniekiaľ zvonku, vyššie v zásobníku. Na úrovni tejto metódy vývojár netuší, či vo vnútri metódy Very UsefulAnd ImportantCode budú nejaké transakcie alebo nie. A ak áno, budú všetky dokončené... Všetci sme tu pre mier a zapuzdrenie, však? Autor metódy „ImportantCode“ by nemal premýšľať o tom, čo sa presne deje vo vnútri metódy, ktorú volá. Ten, v ktorom je transakcia spracovaná nesprávne. V dôsledku toho pokus o prácu s databázou po vyvolaní výnimky z transakcie s najväčšou pravdepodobnosťou povedie k tomu, že "V tejto transakcii, bla bla ..."

Rozmazanie transakcií medzi metódami

Druhé pravidlo kódu „bezpečného pre transakcie“: referenčný počet transakcií na začiatku metódy a na konci musí mať rovnakú hodnotu. Transakciu nemôžete začať jedným spôsobom a ukončiť iným. Pravdepodobne nájdete výnimky z tohto pravidla, ale bude to nejaký nízkoúrovňový kód, ktorý píšu kompetentnejší ľudia. Vo všeobecnosti sa takto nedá písať.


Napríklad:


Procedure ImportantCode() LinkList = GetWhereToLinkList(); Veľmi užitočný&DôležitýKód(Zoznam referencií); CommitTransaction(); // Vstupenka do pekla, vážny rozhovor s autorom o našich ťažkých pracovnoprávnych vzťahoch. EndProcedure

Vyššie uvedené je neprijateľný posratý kód. Nemôžete písať metódy takým spôsobom, aby si volajúci pamätal a sledoval možné (alebo pravdepodobné – kto vie) transakcie v rámci iných metód, ktoré volá. Ide o porušenie zapuzdrenia a rastu špagátového kódu, ktorý nemožno vysledovať pri zachovaní zdravého rozumu.


Obzvlášť zábavné je pripomenúť si, že skutočný kód je oveľa väčší ako syntetické príklady 3 riadkov. Hľadanie začínajúcich a končiacich transakcií šiestimi úrovňami vnorenia – to priam motivuje k srdečným rozhovorom s autormi.

Pokúšame sa opraviť kód

Vráťme sa k pôvodnej metóde a skúsme to napraviť. Hneď musím povedať, že objektový zámok zatiaľ neopravíme, len aby sme neskomplikovali ukážkový kód.

Prvý prístup typickej prezývky 1C

Programátori 1C zvyčajne vedia, že pri zápise môže byť vyvolaná výnimka. Boja sa aj výnimiek, a tak sa ich snažia všetkých chytiť. Napríklad takto:


Postup veľmi užitočný&dôležitýKód(Zoznam referencií) StartTransaction(); Pre každý odkaz zo zoznamu odkazov referenčnej slučky Referenčný objekt = Reference.GetObject(); ReferenceObject.WhichField = "Zmenil som sa z kódu"; Attempt toReferenceObject.Write(); Výnimka Log.Error("Nepodarilo sa zapísať prvok %1", Referencia); Pokračovať; Koniec pokusu; EndCycle; CommitTransaction(); EndProcedure

No, zlepšilo sa to, však? Na Teraz, možné chyby záznamy sa spracúvajú a dokonca zaznamenávajú. Pri písaní objektu sa už nebudú hádzať výnimky. A v logu dokonca vidíte – na akom objekte príliš nelenil, namiesto lakonického „Chyba pri zadávaní adresára“ v správe zobrazil odkaz, ako často radi píšu vývojári, ktorí sa vždy ponáhľajú. Inými slovami, ide o starosť o používateľa a rast kompetencií.


Skúsená prezývka 1C tu však povie, že nie, nezlepšilo sa to. V skutočnosti sa nič nezmenilo a možno ešte horšie. V metóde „Write()“ samotná platforma 1C spustí transakciu zápisu a táto transakcia už bude vnorená vo vzťahu k našej. A ak v čase práce s databázou 1C odvolá svoju transakciu (napríklad sa vyvolá výnimka obchodnej logiky), naša transakcia najvyššej úrovne bude stále označená ako „skazená“ a nebude možné opraviť to. V dôsledku toho tento kód zostane problematický a pri pokuse o potvrdenie sa zobrazí „chyby sa už vyskytli“.


Teraz si predstavte, že nehovoríme o malej metóde, ale o deep call stacku, kde úplne dole niekto zobral a „uvoľnil“ začatú transakciu zo svojej metódy. Procedúry na najvyššej úrovni nemusia ani tušiť, že niekto tam dole začal transakcie. V dôsledku toho sa celý kód zrúti s nezreteľnou chybou, ktorú je v princípe nemožné preskúmať.


Na dokončenie alebo vrátenie transakcie je potrebný kód, ktorý spúšťa transakciu. Bez ohľadu na akékoľvek výnimky. Každá cesta kódu by sa mala preskúmať, aby sa zistilo, či sa metóda ukončí bez potvrdenia alebo prerušenia transakcie.

Metódy práce s transakciami v 1C

Nebolo by zbytočné pripomenúť, že vo všeobecnosti nám 1C poskytuje transakcie, s ktorými môžeme pracovať. Toto sú dobre známe metódy:

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

Prvé 3 metódy sú zrejmé a robia to, čo hovoria vo svojich menách. Posledná metóda vráti hodnotu True, ak je počítadlo transakcií väčšie ako nula.


A je tu zaujímavá funkcia. Metódy ukončenia transakcie (Potvrdiť a Zrušiť) vyvolávajú výnimky, ak je počet transakcií nula. To znamená, že ak niektorému z nich zavoláte mimo transakcie, dôjde k chybe.


Ako správne používať tieto metódy? Veľmi jednoduché: musíte si prečítať pravidlo formulované vyššie:


Ako môžete dodržiavať toto pravidlo? Vyskúšajme:


Vyššie sme už pochopili, že metóda DoSomething je potenciálne nebezpečná. Môže vyvolať nejakú výnimku a transakcia sa „vyplazí“ z našej metódy. Dobre, pridajte možnú obsluhu výnimiek:


StartTransaction(); Pokus o DoSomething(); Výnimka // čo sem napísať? Koniec pokusu; CommitTransaction();

Skvelé, zachytili sme chybu, ktorá sa vyskytuje, ale čo s tým robiť? Napísať správu do denníka? Možno, ak by mal byť kód na zaznamenávanie chýb presne na tejto úrovni a my tu čakáme na chybu. A ak nie? Ak sme tu neočakávali žiadne chyby? Potom by sme mali túto výnimku prejsť vyššie, nech sa s nimi vysporiada iná vrstva architektúry. To sa vykonáva pomocou operátora "CauseException" bez argumentov. V týchto vašich java sipplusoch sa to robí presne rovnakým spôsobom s príkazom throw.


StartTransaction(); Pokus o DoSomething(); Výnimka ThrowException; Koniec pokusu; CommitTransaction();

Takže, počkajte... Ak len posúvame výnimku ďalej, tak prečo vôbec potrebujeme Try? A tu je dôvod, prečo: pravidlo nás núti zabezpečiť dokončenie transakcie, ktorú sme začali.


StartTransaction(); Pokus o DoSomething(); Výnimka CancelTransaction(); ThrowException; Koniec pokusu; CommitTransaction();

Teraz sa zdá, že je to krásne. Pamätáme si však, že nedôverujeme kódu DoSomething(). Zrazu, vnútri jeho autor nečítal tento článok, a nevie, ako pracovať s transakciami? Zrazu to tam vzal a zavolal metódu CancelTransaction, alebo naopak, opravil to? Je to pre nás veľmi dôležité obsluha výnimky nevyvolala novú výnimku, inak sa pôvodná chyba stratí a preskúmanie problémov bude nemožné. A pamätáme si, že metódy Commit a Cancel môžu vyvolať výnimku, ak transakcia neexistuje. Tu sa hodí metóda TransactionActive.

finálna verzia

Nakoniec môžeme napísať správny, „transakčne bezpečný“ kód. Tu je:


**UPD: Komentáre navrhli bezpečnejšiu možnosť, keď sa CommitTransaction nachádza v bloku Pokus. Táto možnosť je zobrazená tu, predtým sa Commit nachádzal za blokom Pokus-Výnimka.


StartTransaction(); Pokus o DoSomething(); CommitTransaction(); Výnimka If TransactionActive() Then CancelTransaction(); Koniec Ak; ThrowException; Koniec pokusu;

Počkajte, nie je to len „Zrušiť transakciu“, čo môže spôsobiť chyby. Prečo potom „CommitTransaction“ nie je zabalený v rovnakom stave ako „TransactionActive“? Opäť platí rovnaké pravidlo: kód, ktorý začal transakciu, by mal byť zodpovedný za jej dokončenie. Naša transakcia nie je nevyhnutne prvá, môže byť vnorená. Na našej úrovni abstrakcie sa od nás vyžaduje iba starostlivosť o našu transakciu. Všetci ostatní by nás nemali zaujímať. Sú to cudzinci, nemali by sme za nich niesť zodpovednosť. Presne tak NIE. Nemali by ste sa pokúšať zistiť skutočnú úroveň počítadla transakcií. To opäť poruší zapuzdrenie a povedie k „rozmazaniu“ logiky riadenia transakcií. Aktivitu sme skontrolovali iba v obslužnom programe výnimiek a iba preto, aby sme sa uistili, že náš obslužný program nevygeneruje novú výnimku, ktorá "skryje" starú.

Kontrolný zoznam pre refaktoring

Pozrime sa na niekoľko najbežnejších situácií, ktoré si vyžadujú zásah do kódu.


vzor:


StartTransaction(); Urob niečo(); CommitTransaction();

Zabaľte to do „bezpečnej“ konštrukcie s výnimkami Retry, Keepalive a Throw.


vzor:


If Not TransactionActive() Then StartTransaction() EndIf

Analýza a Refaktoring. Autor nevedel čo robí. Je bezpečné spustiť vnorené transakcie. Nemusíte kontrolovať stav, stačí spustiť vnorenú transakciu. Dole v module tam asi ešte perverzuje s ich fixáciou. To je zaručené hemoroidy.


Približne podobná možnosť:


If TransactionActive() Then CommitTransaction() EndIf

podobne: zaviazať transakciu podľa podmienky je zvláštne. Prečo je tam podmienka? Čo, túto transakciu už mohol vykonať niekto iný? Dôvod súdneho sporu.


vzor:


StartTransaction() While Selection.Next() Loop // čítanie objektu podľa odkazu // zápis objektu EndCycle; CommitTransaction();
  1. zaviesť riadené uzamykanie, aby sa zabránilo zablokovaniu
  2. zadajte volanie metódy Blok
  3. zabaľte do "vyskúšať", ako je uvedené vyššie

vzor:


StartTransaction() While Selection.Next() Opakovať pokus Object.Write(); Správa o výnimke ("Nepodarilo sa zapísať"); Koniec pokusu; EndCycle; CommitTransaction();

Táto transakcia sa už v prípade výnimky nedokončí. Nemá zmysel pokračovať v cykle. Kód je potrebné prepísať s odkazom na pôvodnú úlohu. Voliteľne uveďte informatívnejšie chybové hlásenie.

Konečne

Ako ste už určite uhádli, patrím k ľuďom, ktorí milujú platformu 1C a vývoj na nej. Samozrejme, existujú sťažnosti na platformu, najmä v prostredí Highload, ale vo všeobecnosti vám umožňuje rýchlo a lacno vyvíjať veľmi kvalitné podnikové aplikácie. Poskytovanie po vybalení a ORM, a GUI, a webové rozhranie, a Reporting, a oveľa viac. V komentároch na Habrého väčšinou napíšu čokoľvek arogantné, a tak, páni, hlavným problémom 1C, ako ekosystémov, nie je platforma ani predajca. Toto je príliš nízky vstupný prah, ktorý umožňuje ľuďom, ktorí nerozumejú, čo je počítač, databáza, klient-server, sieť a všetko ostatné, dostať sa do odvetvia. 1C príliš zjednodušil vývoj podnikových aplikácií. Za 20 minút dokážem napísať účtovný systém pre nákup / predaj s flexibilnými reportmi a webovým klientom. Potom je pre mňa ľahké myslieť si o sebe, že vo veľkom meradle môžete písať takmer rovnakým spôsobom. 1C nejako urobí všetko v sebe, neviem ako, ale pravdepodobne to urobí. Napíšem "StartTransaction ()" ....

Pridať značky