1c 8 transakcije iz zunanjih virov. Enkratne stranke. Segmentacija za ponovne nakupe. Stroški blaga v naročilu

Ne glede na izbrano možnost delovanja (datoteka ali odjemalec-strežnik) sistem 1C:Enterprise zagotavlja delo z informacijami, shranjenimi v bazi podatkov, s pomočjo transakcijskega mehanizma.

Transakcija- gre za nedeljivo zaporedje operacij manipulacije podatkov z vidika vpliva na zbirko podatkov. Deluje po načelu vse ali nič in bazo podatkov premika iz enega celostnega stanja v drugo. Če iz nekega razloga eno od transakcijskih dejanj ni izvedljivo ali pride do neke vrste sistemske motnje, se baza podatkov vrne v stanje pred začetkom transakcije (transakcija se vrne nazaj).

Sistem 1C:Enterprise implicitno kliče transakcije, ko izvaja kakršna koli dejanja, povezana s spreminjanjem informacij, shranjenih v bazi podatkov. V transakciji so na primer poklicani vsi obdelovalci dogodkov, ki se nahajajo v modulih objektov in naborov zapisov, povezanih s spreminjanjem podatkov baze podatkov. Transakcija bere tudi objekte naslednjih vrst: Predmet Planobena, Dokument -predmet letala, referenčna knjiga, Planwid -Charactermentary in Planword Calculations, Plan -Counter -subject, Board Procedure, Object, Squeezers, Register of Register, Register -Knock -Racing, Registachgontinarinapers, Registracija registracije, Ponovno poročanje , preračunljivo. V tem primeru se v načinu upravljanega zaklepanja namesti skupna ključavnica z vrednostjo registra za nize zapisov in z izbirnimi vrednostmi za niz zapisov neodvisnega informacijskega registra.

Poleg tega lahko razvijalec uporablja eksplicitno delo s transakcijami. Če želite to narediti, uporabite postopke globalnega konteksta StartTransaction(), CommitTransaction() in CancelTransaction().

Uporaba eksplicitnega transakcijskega klica

Metoda StartTransaction() omogoča odpiranje transakcije. Vse spremembe informacij baze podatkov, narejene z nadaljnjimi izjavami, se lahko nato v celoti sprejmejo ali v celoti zavrnejo. Če želite sprejeti vse spremembe, uporabite metodo Izvedi transakcijo(). Če želite razveljaviti vse spremembe, narejene v odprti transakciji, uporabite metodo Prekliči transakcijo(). Če je število klicev metode StartTransaction() presega število klicev metode Izvedi transakcijo() oz Prekliči transakcijo(), potem bo sistem izvedel implicitni klic metode Prekliči transakcijo() v naslednjih primerih:

● ob koncu izvajanja vgrajenega jezika (upravljalnik dogodkov, zunanja povezava, strežnik za avtomatizacijo);

● pri prenosu nadzora s strežnika na odjemalca.

Če je število klicev metode CommitTransaction() oz Prekliči transakcijo() presega število klicev metode StartTransaction(), nato pa pri izvajanju nepotrebnega klica metode Izvedi transakcijo() oz Prekliči transakcijo() vržena bo izjema. Tako je shema za delo s transakcijo v splošni pogled lahko izgleda takole:

Poskus

StartTransaction();

// Zaporedje izjav

Izvedi transakcijo();

Izjema

Prekliči transakcijo();

EndAttempt;

Pri uporabi takšne sheme se morate zavedati, da sistem ne obdeluje vseh napak, ki se pojavijo pri delu z bazo podatkov, na enak način. Na splošno lahko vse napake baze podatkov razdelimo v dve kategoriji:

● nepopravljivo,

● vračljivo.

Nepopravljive napake- to so napake, če se pojavijo, je lahko moteno normalno delovanje sistema 1C:Enterprise, na primer podatki so lahko poškodovani. Če pride do nepopravljive napake, se izvajanje sistema 1C:Enterprise v vsakem primeru prekine. Če med izvajanjem transakcije pride do nepopravljive napake, sistem prekliče vse spremembe, narejene kot del te transakcije.

Popravljive napake- to so napake, ki ne povzročajo resnih motenj v delovanju sistema 1C: Enterprise. Če pride do popravljive napake, se lahko nadaljnje delovanje sistema nadaljuje. V tem primeru se seveda prekine sama operacija, ki je povzročila napako, in pojavi se izjema, ki jo lahko prestreže in obdela konstrukt

Poskus ... Izjema ... Konec poskusa.

Klic ugnezdene transakcije

Znotraj transakcije, ki je že v teku, lahko dostopate do postopkov StartTransaction(), CommitTransaction() in Prekliči transakcijo(). Uporabite lahko na primer naslednji klicni vzorec:

StartTransaction();

StartTransaction();

Izvedi transakcijo();

// Ugnezdeni transakcijski klic

StartTransaction();

Izvedi transakcijo();

Izvedi transakcijo();

Vendar pa tak klic ne pomeni začetka nove transakcije v okviru že teče.

POZOR!Sistem 1C:Enterprise ne podpira ugnezdenih transakcij.To pomeni, da je vedno veljavna samo transakcija sama. najvišji nivo.

Vse transakcije, klicane znotraj že odprte transakcije, so dejansko del iste transakcije in ne tvorijo ugnezdene transakcije. Tako razveljavitev sprememb, izvedenih v ugnezdeni transakciji, na koncu ne bo razveljavila sprememb v sami ugnezdeni transakciji, temveč vse spremembe v transakciji najvišje ravni. Hkrati se spremembe potrditve, narejene v ugnezdeni transakciji, prezrejo.

Vpliv transakcij na delovanje programskih objektov

Na splošno so programski objekti, ki jih uporablja sistem 1C:Enterprise, popolnoma pregledni za transakcije baze podatkov. Z drugimi besedami, transakcije baze podatkov se lahko kličejo med izvajanjem različne metode objekti programske opreme vendar na primer dejanja, ki jih izvede baza podatkov pri povrnitvi transakcije, na splošno ne vplivajo na ustrezno programsko opremo predmetov.

Iz tega sledi, da mora razvijalec ob preklicu transakcij baze podatkov (če je potrebno) samostojno zagotoviti ustrezne spremembe podatkov ustreznega programsko opremo predmetov. To lahko storite s ponovnim branjem vseh podatkov o objektu ali s spremembo nekaterih podrobnosti o objektu programa.

Obstajajo izjeme od tega pravila. Zaradi pomembne specifičnosti uporabe programskih predmetov sistema 1C:Enterprise lahko v nekaterih primerih povrnitev sprememb, narejenih v bazi podatkov, še vedno vpliva na vrednosti lastnosti ustreznega programsko opremo predmetov. To se zgodi v naslednjih primerih:

● ob preklicu transakcije atribut knjiženja dokumenta obnovi vrednost, ki je bila pred začetkom transakcije;

● če je bil predmet ustvarjen in zapisan v transakciji, potem se pri povrnitvi transakcije referenčna vrednost počisti;

● če je bil objekt ustvarjen izven transakcije in je bila pri evidentiranju v transakciji uporabljena samodejno generirana koda/številka, se ob preklicu transakcije koda/številka izbriše.

2017-08-12

Ustvarite transakcije po meri za vzdrževanje objektov OM.

Uvod

Mislim, da se je veliko funkcionalnih svetovalcev SAP srečalo s transakcijo vzdrževanja objektov organizacijskega upravljanja. Transakcija namreč PP01

Uporaba te transakcije daje uporabniku možnost skrbništva informacijskih tipov organizacijskega upravljanja za tiste tipe objektov, ki se uporabljajo v poslovnih procesih, ki se avtomatizirajo. Zelo pogosto se ta transakcija uporablja kot enotna vstopna točka za delo z vsemi vrstami objektov organizacijskega upravljanja, kar v resnici ni zelo dobra praksa. No, ali pa ni zelo priročno. Čeprav je vsekakor pogosta. Nato vam bom poskušal povedati, kakšna alternativa bi lahko obstajala.

Tabela T77S0, skupina "TCODE"

Ko nastavljate objekte OM, se boste verjetno dotaknili nastavitve, ki se nahaja na naslednji poti v SPRO:

IMG: Upravljanje osebja -> Organizacijsko upravljanje -> Osnovne nastavitve -> Izboljšava podatkovnega modela -> Ohranjanje tipov objektov

Tukaj ustvarite nove objekte OM, jim izmislite imena, izberete ikone in določite nekaj nastavitev zanje ... Trenutno nas zanima vozlišče " Tip predmeta Ključ + Transakcija"

Pred vami se bo odprl del pogleda nastavitev T77S0 s filtriranimi vrednostmi skupine

Vredno pozornosti na skupino TCODE v katerem, če natančno pogledate, lahko najdete tehnična imena transakcij, s katerimi ste najverjetneje morali delati. Še več, v stolpcu Vrednost označuje vrsto predmeta, za katerega je določena transakcija namenjena.

Kaj je posebnega pri teh transakcijah?

Z uporabo transakcij, ki so zasnovane za vzdrževanje določene vrste predmeta, vam ni več treba izbrati prav teh vrst objektov, ki so privzeto na voljo v transakciji PP01. To je z uvedbo na primer transakcije PO09, takoj začnete delati s predmeti, kot je L

Ustvarjanje nove transakcije za lasten objekt organizacijskega upravljanja

V eni od svojih prejšnjih objav sem govoril o tem, kako lahko ustvarite nov objekt OM in mu dodate strukturno iskanje

Ne bom šel daleč od tega gradiva. Kot predstavitev bom ustvaril novo transakcijo za vzdrževanje predmeta 91.

Definiranje novega tipa objekta v T77S0

V pogledu nastavitev določite ime prihodnje transakcije T77S0

Vrednost »ZP91M« je v tem primeru ime bodoče transakcije za vzdrževanje objekta 91 . Shranite spremembe.

Ustvarjanje nove transakcije za vzdrževanje objekta OM

Preko transakcije SE93 ustvarite transakcijo za vzdrževanje vašega predmeta. Spodaj je video fragment z zaporedjem dejanj, ki jih je treba izvesti za ustvarjanje ustrezne transakcije

Upoštevajte vrednosti, ki so bile uporabljene za polja Program, Številka zaslona,Objekt avtorizacije. Zdaj začnite novo transakcijo

Uporabnik ima možnost dela samo z določeno vrsto predmeta, ki ga v določenem smislu lahko imenujemo udobje, in, če želite, minimiziranje dodatnih dejanj za izbiro želenega predmeta.

Zadnjič, ko smo pogledali najenostavnejši način z uporabo vgrajenega jezika 1C. Na praksi transakcije veliko pogosteje uporablja v povezavi z oblikovanjem. To omogoča, da v primeru napake nadaljujete z izvajanjem kode, kot tudi zagotovite ustrezno sporočilo o napaki uporabniku in zapišete informacije v dnevnik registracije ali v datoteko dnevnika za kasnejšo analizo s strani skrbnika sistema.

Če se obrnemo na tehnično dokumentacijo ali disk ITS, bomo videli, da 1C priporoča naslednji način organizacije transakcije v poskusu

Poskus //1. Začetek transakcije. StartTransaction() ; //2. Blok operacij, izvedenih v transakciji. //3. Če so vse operacije uspešne, transakcijo potrdimo. CommitTransaction() ; Izjema //4. Če med izvajanjem kode pride do napak, prekličite transakcijo. CancelTransaction() ; //5. Po potrebi zabeležite v dnevnik. //6. Po potrebi prikažite sporočilo uporabniku. EndAttempt ;

Pravzaprav koda ne zahteva posebne razlage. Če poteka poskusi Pri izvajanju transakcijske kode pride do napake, takoj pademo v blok izjema, tj. pred metodo Izvedi transakcijo() preprosto ne pridemo tja. No, izjemoma transakcijo ustrezno prekličemo in po potrebi prikažemo sporočilo o napaki ter podatke zapišemo v dnevnik. Zelo zaželeno je, da se napake beležijo v dnevniku, zlasti pri tistih operacijah, ki se izvajajo brez sodelovanja uporabnika (na primer rutinska opravila). To vam bo omogočilo kasnejšo analizo napake. Namesto beleženja lahko uredite pošiljanje sporočil skrbniku po elektronski pošti.

Zdaj, oboroženi z novim znanjem, poskusimo spremeniti kodo, obravnavano v članku o . Naj vas spomnim, da smo upoštevali vpis v imenik Blago in v informacijski register Cena po naslednji shemi:

&Na strežniku brez konteksta StartTransaction() ; //posnemite nov izdelek Izdelek = Imeniki. Blago. CreateItem() ; Izdelek. Name = "Luknjač" ; Izdelek. Napiši(); //zapišite ceno RecordSet = InformationRegisters. Cena. CreateRecordSet() ; NewRecord = RecordSet. Dodaj(); NewRecord. Obdobje = TrenutniDatum() ; NewRecord. Izdelek = Izdelek. Povezava; NewRecord. Znesek = 100 ; RecordSet. Napiši(); CommitTransaction() ; Konec postopka

Zdaj pa postavimo transakcijo v blok Poskus izjeme. Najverjetneje lahko pride do napak le pri zapisovanju v imenik ali informacijski register, torej predhodna priprava Vzemimo to zunaj transakcije.

&Na strežniku brez konteksta Postopek RunTransactionOnServer() //ustvari nov izdelek Izdelek = Imeniki. Blago. CreateItem() ; Izdelek. Name = "Luknjač" ; //Ustvari zapis s ceno RecordSet = InformationRegisters. Cena. CreateRecordSet() ; NewRecord = RecordSet. Dodaj(); NewRecord. Obdobje = TrenutniDatum() ; NewRecord. Znesek = 100 ; //Izvedba transakcije v poskusu Poskus zagona transakcije(); Izdelek. Napiši(); NewRecord. Izdelek = Izdelek. Povezava; RecordSet. Napiši(); CommitTransaction() ; Izjema CancelTransaction() ; Sporočilo = Novo sporočiloUporabniku; Sporočilo. Besedilo = ; Sporočilo. Poročati() ; LogRegistration( "Pri beleženju izdelka in njegove cene je prišlo do napake") ; EndAttempt ; Konec postopka

Česa NE storiti

Tisti, ki se šele začenjajo ukvarjati s transakcijami, imajo pogosto željo, da to počnejo na ta način

StartTransaction() ; Poskus zagona transakcije(); //Operacijski blok CommitTransaction() ; Izjema CancelTransaction() ; EndAttempt ; Poskus zagona transakcije(); //Operacijski blok CommitTransaction() ; Izjema CancelTransaction() ; EndAttempt ; CommitTransaction() ;

Ali v zanki

StartTransaction() ; Za vsak poskus zanke Data From Data Array Loop to Start Transaction() ; podatki. Napiši(); CommitTransaction() ; Izjema CancelTransaction() ; EndAttempt ; Končni cikel ; CommitTransaction() ;

Na prvi pogled smo naredili vse v skladu s priporočili podjetja 1C. Toda dejstvo je, da platforma 1C ne podpira ugnezdenih transakcij. Se pravi, čisto tehnično se da tako napisati. Toda hkrati vse ugnezdene transakcije ne tvorijo novih, ampak pripadajo isti transakciji najvišje ravni. Na ta način, če ena od ugnezdenih transakcij ne uspe, naslednje ugnezdene transakcije ni mogoče potrditi. Sistem bo prikazal sporočilo, kot je: "V tej transakciji je že prišlo do napak!". Pokažimo to s primerom. Recimo, da se odločimo evidentirati dve dobrini, vsako v svoji transakciji. In naredimo te transakcije ugnezdene v tretjem. Nato bomo z metodo umetno povzročili napako v prvi transakciji Dvigni izjemo:

&Na strežniku brez konteksta Postopek RunTransactionOnServer() StartTransaction() ; Poskus zagona transakcije(); Izdelek = Imeniki. Blago. CreateItem() ; Izdelek. Ime = "Tabela" ; Izdelek. Napiši(); Dvigni izjemo "Napaka pri vnosu izdelka."; CommitTransaction() ; Izjema CancelTransaction() ; Sporočilo = Novo sporočiloUporabniku; Sporočilo. Besedilo = Opis Napake() PoskusZačetkaTransakcije() ; Izdelek = Imeniki. Blago. CreateItem() ; Izdelek. Ime = "Stol" ; Izdelek. Napiši(); CommitTransaction() ; Izjema CancelTransaction() ; Sporočilo = Novo sporočiloUporabniku; Sporočilo. Besedilo = Opis napake() ; Sporočilo. Poročati() ; EndAttempt ; CommitTransaction() ; Konec postopka

Kot rezultat izvedbe tega postopka bomo v oknu s sporočilom videli naslednje:

(ExternalProcessing.TransactionsAtTrying.Form.Form.Form(20)): Napaka pri pisanju postavke. (ExternalProcessing.TransactionsAtTrying.Form.Form.Form(40)): Napaka pri klicu kontekstne metode (Write): V tej transakciji je že prišlo do napak!

Tako je organiziranje ugnezdenih transakcij v 1C popolnoma nesmiselno.

Možne možnosti

Zdaj pa se vrnimo k možnosti, kjer smo zabeležili izdelek in ceno zanj. Če pride do napake pri izvedbi transakcije, bomo težko razumeli, na kateri točki je do nje prišlo - pri zapisu izdelka ali pri zapisu cene, saj se oboje zgodi v istem poskusu. Da ugotovimo, kje je prišlo do napake, moramo vsako operacijo pisanja zaviti v svoj poskus in se izogniti ugnezdenim transakcijam. Da bi to naredili, uvedemo logično spremenljivko Zavrnitev in glede na njegovo vrednost ob koncu vseh operacij bomo izvršili ali preklicali transakcijo.

&Na strežniku brez konteksta Postopek RunTransactionOnServer() // Začetek transakcije Zavrni = False; StartTransaction() ; // Poskušam posneti izdelek Poskus izdelka = Imeniki. Blago. CreateItem() ; Izdelek. Name = "Luknjač" ; Izdelek. Napiši(); Napaka izjeme = True; Sporočilo = Novo sporočiloUporabniku; Sporočilo. Besedilo = "Napaka pri snemanju izdelka"; Sporočilo. Poročati() ; EndAttempt ; // Poskušamo zabeležiti ceno AttemptRecordSet = InformationRegisters. Cena. CreateRecordSet() ; NewRecord = RecordSet. Dodaj(); NewRecord. Obdobje = TrenutniDatum() ; NewRecord. Izdelek = Izdelek. Povezava; NewRecord. Znesek = 100 ; RecordSet. Napiši(); Napaka izjeme = True; Sporočilo = Novo sporočiloUporabniku; Sporočilo. Besedilo = "Napaka pri beleženju cene"; Sporočilo. Poročati() ; EndAttempt ; // Potrdi ali prekliči transakcijo If NOT Failure Then CommitTransaction() ; Else CancelTransaction() ; EndIf ; Konec postopka

Enako lahko naredimo, ko ponavljamo in zapisujemo podatke v zanki. V tem primeru bomo lahko pridobili seznam vseh podatkov z napakami, če obstajajo.

V pripravah na certificiranje 1C Expert, na predvečer dveh zelo pomembnih in globalnih tem - blokiranja, bi rad pogledal nekaj, brez česar so zgornji koncepti nemogoči - transakcijo DBMS.

Transakcija- logično povezano, nedeljivo zaporedje dejanj. Transakcija se lahko zaključi v celoti ali pa sploh ne. Za potrditev transakcije v DBMS se uporablja metoda COMMIT.

Tipičen primer transakcije je nakazilo denar iz enega računa v drugega:

  1. začeti transakcijo;
  2. preberite višino sredstev na računu številka 123;
  3. zmanjšajte stanje na računu 123 za 100 rubljev;
  4. shranite stanje na računu številka 123;
  5. odčitajte višino sredstev na računu številka 321;
  6. povečajte svoje stanje za 100 rubljev;
  7. nov znesek sredstev evidentira na kontu 321;
  8. izvrši transakcijo.

Pridobite 267 video lekcij o 1C brezplačno:

Kot lahko vidimo, če transakcija ni dokončana v celoti, potem nima pomena.

Ključne zahteve (ACID) za transakcijski DBMS

Eden najpogostejših sklopov zahtev za transakcije in transakcijske DBMS je niz ACID (Atomicity, Consistency, Isolation, Durability). To so lastnosti, ki jih mora imeti vsaka transakcija:

  • Atomičnost— nobena transakcija ne sme biti evidentirana delno;
  • Doslednost- sistem je v konsistentnem stanju pred začetkom transakcije in mora ostati v konsistentnem stanju tudi po zaključku transakcije;
  • Izolacija— med izvajanjem transakcije vzporedne transakcije ne smejo vplivati ​​na njen rezultat;
  • Vzdržljivost- v primeru okvare morajo spremembe, ki jih je naredila uspešno opravljena transakcija, ostati shranjene po ponovni vzpostavitvi delovanja sistema.

Transakcije v 1C

Transakcije v 1C 8.3 in 8.2 so ustvarjene samodejno in opisane s strani razvijalcev.

Z metodo TransactionActive() lahko ugotovite, ali je transakcija aktivna.

Primer samodejne transakcije je obdelava knjiženja dokumenta, pisanje imeniške postavke v bazo podatkov, pisanje nabora zapisov registra informacij itd.

Naslov je bil privlačen, a je prekipelo. Takoj bom rekel, da bomo govorili o 1C. Dragi uporabniki 1C, ne veste, kako delati s transakcijami in ne razumete, kaj so izjeme. Do tega zaključka sem prišel s pregledovanjem veliko število Koda 1C, rojena v divjini domačega podjetja. IN tipične konfiguracije vse to je dovolj dobro, vendar je grozljiva količina kode po meri napisana nekompetentno z vidika zbirke podatkov. Ste že kdaj videli napako »Ta transakcija je že naletela na napake«? Če da, potem naslov članka velja tudi za vas. Končno ugotovimo, kaj so transakcije in kako jih pravilno obravnavati pri delu z 1C.

Zakaj bi morali sprožiti alarm?

Najprej ugotovimo, kaj je napaka »V tej transakciji je že prišlo do napak«. To je pravzaprav izjemno preprosta stvar: poskušate delati z bazo znotraj že povrnjene (preklicane) transakcije. Na primer, nekje je bila poklicana metoda CancelTransaction, vi pa jo poskušate potrditi.


Zakaj je to slabo? Ker to napako ne pove ničesar o tem, kje se je težava dejansko zgodila. Ko podpora prejme posnetek zaslona s takšnim besedilom od uporabnika in še posebej za kodo strežnika, s katerim človek ne dela interaktivno, je ... Hotel sem napisati "kritična napaka", pa sem mislil, da je to modna beseda, na katero nihče več ne posveča pozornosti ... To je rit. To je programska napaka. To ni naključna napaka. To je napaka, ki jo je treba takoj odpraviti. Kajti ko se vaši strežniški procesi v ozadju ponoči izklopijo in začne podjetje hitro izgubljati denar, potem je »V tej transakciji že prišlo do napak« zadnja stvar, ki jo želite videti v diagnostičnih dnevnikih.


Seveda obstaja možnost, da bo tehnološki dnevnik strežnika (vključen je v produkciji, kajne?) nekako pomagal diagnosticirati težavo, vendar trenutno ne morem pomisliti na možnost na pamet - kako točno da bi v njem našli pravi vzrok te napake. Toda pravi razlog je eden - programer Vasya je prejel izjemo v transakciji in se odločil, da enkrat ni slaba ideja, "samo pomislite, to je napaka, gremo naprej."

Kaj so transakcije v 1C

Nerodno je pisati o elementarnih resnicah, a očitno bo treba malo. Transakcije v 1C so enake transakcijam v DBMS. To niso neke posebne transakcije "1C", to so transakcije v DBMS. Glede na splošno idejo o transakcijah se lahko izvršijo v celoti ali pa se sploh ne izvršijo. Vse spremembe tabel baze podatkov, narejene znotraj transakcije, je mogoče takoj razveljaviti, kot da se ni nič zgodilo.


Nato morate razumeti, da 1C ne podpira ugnezdenih transakcij. Pravzaprav niso podprti "v 1C", ampak sploh niso podprti. Vsaj tiste DBMS, s katerimi lahko deluje 1C. Ugnezdene transakcije na primer ne obstajajo v MS SQL in Postgres. Vsak "ugnezdeni" klic StartTransaction preprosto poveča števec transakcij in vsak klic "CommitTransaction" ta števec preprosto zmanjša. To vedenje je opisano v številnih knjigah in člankih, vendar sklepi iz tega vedenja očitno niso dovolj analizirani. Strogo gledano, v SQL obstaja tako imenovani. SAVEPOINT, vendar jih 1C ne uporablja in ta zadeva je precej specifična.



Postopek Zelo uporabna in pomembna koda (seznam povezav imenika) StartTransaction(); Za vsako povezavo s seznama imeniških povezav Loop Directory Object = Link.GetObject(); Imenik Object.SomeField = "Bil sem spremenjen iz programske kode"; Imeniški objekt.Write(); EndCycle; Izvedi transakcijo(); Konec postopka

Koda v angleščini

res ne. Absolutno ne želim podvajati primerov v angleščini samo zato, da bi zabaval ljubitelje svetih vojn in svetih vojn.


Verjetno pišete takšno kodo, kajne? Navedeni primer kode vsebuje napake. Vsaj tri. Veste katere? Takoj bom povedal o prvem, povezan je z zaklepanjem objektov in ni neposredno povezan s transakcijami. O drugem - malo kasneje. Tretja napaka je zastoj, ki se bo pojavil med vzporednim izvajanjem te kode, vendar je to tema za ločen članek, zdaj je ne bomo obravnavali, da ne bi zapletali kode. Ključna beseda za googlanje: zaporne ključavnice.


Upoštevajte, da je koda preprosta. Tega je preprosto veliko v vaših sistemih 1C. In vsebuje vsaj 3 napake hkrati. Pomislite v prostem času, koliko napak je v bolj zapletenih scenarijih za delo s transakcijami, ki so jih napisali vaši 1C programerji :)

Objektne ključavnice

Torej, prva napaka. V 1C obstajajo objektne ključavnice, tako imenovane "optimistične" in "pesimistične". Ne vem kdo je skoval izraz, jaz bi ga ubil :). Popolnoma nemogoče si je zapomniti, kdo od njih je odgovoren za kaj. O njih je bilo podrobno pisano, pa tudi v drugi splošni IT literaturi.


Bistvo težave je v tem, da je v navedenem primeru kode predmet baze podatkov spremenjen, v drugi seji pa je morda interaktivni uporabnik (ali sosednja nit v ozadju), ki bo prav tako spremenil ta objekt. Tukaj lahko eden od vas prejme napako "vnos je bil spremenjen ali izbrisan." Če se to zgodi v interaktivni seji, se bo uporabnik praskal po zadnjici, preklinjal in poskušal znova odpreti obrazec. Če se to zgodi v niti v ozadju, boste morali to poiskati v dnevnikih. In ladijski dnevnik je, kot veste, počasen in le nekaj ljudi v naši panogi je postavilo sklad ELK za dnevnike 1C ... (mimogrede, smo med tistimi, ki postavljajo in pomagajo drugim pri namestitvi :) )


Skratka, to je moteča napaka in bolje je, da je nimate. Zato razvojni standardi jasno navajajo, da je treba pred spreminjanjem predmetov na njih namestiti ključavnico predmeta z uporabo " Imeniški objekt.Lock()". Nato sočasna seja (ki mora tudi to narediti) ne bo mogla začeti operacije posodabljanja in bo prejela pričakovano, nadzorovano napako.

In zdaj o transakcijah

S prvo napako smo se ukvarjali, pojdimo na drugo.


Če v tej metodi ne omogočite preverjanja izjem, vas bo izjema (na primer zelo verjetno v metodi "Write()") vrgla iz ta metoda brez dokončanja transakcije. Izjema od metode »Write« se lahko sproži zaradi različnih razlogov, na primer, sprožijo se nekatera preverjanja aplikacije v poslovni logiki ali pride do zgoraj omenjenega zaklepanja objekta. Kakorkoli, druga napaka pravi: Koda, ki je transakcijo začela, ni odgovorna za njeno dokončanje.



Točno tako bi jaz imenoval ta problem. V naš statični analizator kode 1C, ki temelji na SonarQube, smo celo ločeno vgradili takšno diagnostiko. Zdaj delam na njegovem razvoju in domišljija programerjev 1C, katerih koda pride k meni v analizo, me včasih pusti v šoku in strahu ...


Zakaj? Ker izjema, vržena na vrhu znotraj transakcije, v 90 % primerov ne bo omogočila izvršitve te transakcije in bo povzročila napako. Treba je razumeti, da 1C samodejno vrne nedokončano transakcijo šele po vrnitvi s kode skripta na raven kode platforme. Dokler ste na ravni kode 1C, transakcija ostane aktivna.


Pojdimo eno raven višje v skladu klicev:


Postopek ImportantCode() LinkList = GetLinkListWhere(); Zelo uporabnainpomembnakoda(seznam povezav); Konec postopka

Poglej kaj se zgodi. Naša problematična metoda je klicana od nekje zunaj, višje v skladu. Na ravni te metode razvijalec nima pojma, ali bodo znotraj metode Zelo uporabne in pomembne kode izvedene transakcije ali ne. In če bodo, ali bodo vsi dokončani ... Vsi smo tukaj zaradi miru in enkapsulacije, kajne? Avtor metode "ImportantCode" ne bi smel razmišljati o tem, kaj točno se zgodi znotraj metode, ki jo kliče. Isti, v katerem je transakcija napačno obdelana. Posledično bo poskus dela z bazo podatkov, potem ko je bila vržena izjema znotraj transakcije, najverjetneje povzročil naslednje: "V tej transakciji bla bla ..."

Širjenje transakcij med metodami

Drugo pravilo kode, ki je varna za transakcije: Referenčno število transakcij na začetku in na koncu metode mora imeti enako vrednost. Transakcije ne morete začeti z eno metodo in je končati z drugo. Verjetno je mogoče najti izjeme od tega pravila, vendar bo to nekakšna koda na nizki ravni, ki jo bodo napisali bolj kompetentni ljudje. Na splošno se tako ne da pisati.


Na primer:


Postopek ImportantCode() LinkList = GetLinkListWhere(); Zelo uporabnainpomembnakoda(seznam povezav); Izvedi transakcijo(); // Vstopnica v pekel, resen pogovor z avtorjem o naših zapletenih delovnih razmerjih. Konec postopka

Zgoraj navedeno je nesprejemljiva koda. Metod ne morete napisati tako, da bi si klicatelj zapomnil in spremljal možne (ali verjetne - kdo ve) transakcije znotraj drugih metod, ki jih kliče. To je kršitev enkapsulacije in širjenje špageti kode, ki je ni mogoče izslediti z zdravo pametjo.


Še posebej zabavno se je spomniti, da je prava koda veliko večja od sintetičnih 3-vrstičnih primerov. Iskanje začetnih in končnih transakcij na šestih ravneh gnezdenja - to neposredno motivira intimne pogovore z avtorji.

Poskušam popraviti kodo

Vrnimo se k prvotni metodi in jo poskusimo popraviti. Takoj bom rekel, da za zdaj ne bomo popravili zaklepanja predmeta, samo da ne bi zapletli vzorčne kode.

Prvi pristop tipičnega vzdevka 1C

Običajno programerji 1C vedo, da se lahko med snemanjem vrže izjema. Bojijo se tudi izjem, zato jih poskušajo ujeti vse. Na primer takole:


Postopek Zelo uporabna in pomembna koda (seznam povezav imenika) StartTransaction(); Za vsako povezavo s seznama imeniških povezav Loop Directory Object = Link.GetObject(); Imenik Object.SomeField = "Bil sem spremenjen iz programske kode"; AttemptDirectoryObject.Write(); Izjema Log.Error("Ni bilo mogoče zapisati elementa %1", Povezava); Nadaljuj; EndAttempt; EndCycle; Izvedi transakcijo(); Konec postopka

No, stvari so se izboljšale, kajne? Konec koncev, zdaj možne napake zapisi se obdelujejo in celo beležijo. Pri pisanju predmeta ne bodo več vržene izjeme. In v dnevniku lahko celo vidite, na katerem predmetu, nisem bil preveč len in sem v sporočilo vključil povezavo namesto lakoničnega »Napaka pri pisanju imenika«, kot pogosto radi pišejo razvijalci, ki se jim vedno mudi. Povedano drugače, prisotna je skrb za uporabnika in dvig kompetenc.


Vendar pa bo izkušeni uporabnik 1C rekel, da ne, ni se izboljšalo. Pravzaprav se ni nič spremenilo, mogoče celo poslabšalo. Pri metodi »Write()« bo platforma 1C sama začela transakcijo pisanja in ta transakcija bo že ugnezdena glede na našo. In če se med delom z bazo podatkov 1C transakcija vrne nazaj (na primer vrže se izjema poslovne logike), bo naša transakcija na najvišji ravni še vedno označena kot "poškodovana" in je ni mogoče potrditi. Posledično bo ta koda ostala problematična in ko jo boste poskušali potrditi, bo prikazano »napake so se že pojavile«.


Zdaj pa si predstavljajte, da ne govorimo o majhni metodi, ampak o globokem skladu klicev, kjer čisto na dnu nekdo vzame in "izpusti" začeto transakcijo iz svoje metode. Postopki na najvišji ravni morda nimajo pojma, da je kdo tam spodaj začel transakcije. Posledično celotna koda odpove z nejasno napako, ki je načeloma ni mogoče raziskati.


Koda, ki začne transakcijo, je potrebna za njeno dokončanje ali razveljavitev. Ne glede na morebitne izjeme. Vsako vejo kode je treba pregledati, da se ugotovi, ali metoda zapusti, ne da bi izvršila ali preklicala transakcijo.

Metode dela s transakcijami v 1C

Ne bi bilo odveč, če vas spomnimo, kaj nam 1C na splošno ponuja za delo s transakcijami. To so dobro znane metode:

  • StartTransaction()
  • Izvedi transakcijo()
  • Prekliči transakcijo()
  • TransactionActive()

Prve 3 metode so očitne in delujejo tako, kot pove njihova imena. Zadnja metoda vrne True, če je števec transakcij večji od nič.


In obstaja zanimiva lastnost. Metode izhoda iz transakcije (Commit in Cancel) vržejo izjeme, če je število transakcij nič. Če enega od njih pokličete zunaj transakcije, bo prišlo do napake.


Kako pravilno uporabiti te metode? Zelo preprosto: prebrati morate zgoraj formulirano pravilo:


Kako upoštevati to pravilo? Poskusimo:


Že zgoraj smo razumeli, da je metoda Naredi nekaj potencialno nevarna. Lahko vrže kakšno izjemo in transakcija bo "prilezla" iz naše metode. V redu, dodajmo možno obravnavo izjem:


StartTransaction(); Poskusi DoSomething(); Izjema // ampak kaj naj tukaj napišem? EndAttempt; Izvedi transakcijo();

Odlično, odkrili smo napako, ki se je pojavljala, toda kaj naj storimo glede tega? Napisati sporočilo v dnevnik? No, mogoče, če bi bila koda za beleženje napak točno na tej ravni in tukaj čakamo na napako. In če ne? Kaj pa, če tukaj ne bi pričakovali napak? Potem bi morali to izjemo prepustiti in pustiti, da se z njo ukvarja druga plast arhitekture. To se izvede z operatorjem "CauseException" brez argumentov. V teh vaših Javascriptih se to naredi na povsem enak način z operatorjem za vrnitev.


StartTransaction(); Poskusi DoSomething(); Izjema ThrowException; EndAttempt; Izvedi transakcijo();

Torej, počakajte ... Če samo vržemo izjemo naprej, zakaj potem sploh obstaja potreba po poskusu? Evo zakaj: pravilo nas sili, da zagotovimo dokončanje transakcije, ki smo jo začeli.


StartTransaction(); Poskusi DoSomething(); ExceptionCancelTransaction(); throwException; EndAttempt; Izvedi transakcijo();

Zdaj se zdi, da je lepo. Vendar se spomnimo, da kodi Do Something() ne zaupamo. Kaj pa, če avtor ni prebral tega članka in ne ve, kako delati s transakcijami? Kaj pa, če ga je vzel tja in poklical metodo CancelTransaction ali, nasprotno, jo zavezal? Za nas je to zelo pomembno obravnavalec izjeme ni vrgel nove izjeme, sicer bo izvirna napaka izgubljena in odpravljanje težav bo nemogoče. In spomnimo se, da lahko metodi Commit in Cancel sprožita izjemo, če transakcija ne obstaja. Tukaj pride prav metoda TransactionActive.

Končna verzija

Končno lahko napišemo pravilno, "transakcijsko varno" različico kode. Tukaj je:


**UPD: komentarji so predlagali varnejšo možnost, ko se CommitTransaction nahaja znotraj bloka Attempt. Ta posebna možnost je prikazana tukaj; prej je bila popravek nameščena za blokom Attempt-Exception.


StartTransaction(); Poskusi DoSomething(); Izvedi transakcijo(); Izjema If TransactionIsActive() Then CancelTransaction(); endIf; throwException; EndAttempt;

Počakajte, vendar ni samo »CancelTransaction« tisto, kar lahko povzroči napake. Zakaj potem »CommitTransaction« ni zavit v enakem stanju kot »TransactionActive«? Ponovno z uporabo istega pravila: Koda, ki je začela transakcijo, bi morala biti odgovorna za njeno dokončanje. Naša transakcija ni nujno prva; lahko je ugnezdena. Na naši ravni abstrakcije se od nas zahteva samo skrb za našo transakcijo. Vsi drugi nas ne bi smeli zanimati. So tujci, ne bi smeli biti odgovorni zanje. Natančno NE SMEJO. Ne poskušajte določiti dejanske ravni števca transakcij. To bo znova prekinilo enkapsulacijo in povzročilo "razmazovanje" logike upravljanja transakcij. Preverili smo samo aktivnost v obdelovalniku izjem in samo zato, da bi se prepričali, da naš obravnavalec ne bo ustvaril nove izjeme, ki bi »skrila« staro.

Kontrolni seznam za preoblikovanje

Oglejmo si nekaj najpogostejših situacij, ki zahtevajo posredovanje kode.


vzorec:


StartTransaction(); Naredi kaj(); Izvedi transakcijo();

Zavijte ga v »varen« dizajn s poskusom, ohranjanjem pri življenju in vrženjem izjeme.


vzorec:


If NotTransactionActive() ThenStartTransaction()EndIf

Analiza in preoblikovanje. Avtor ni razumel, kaj počne. Varno je začeti ugnezdene transakcije. Pogoja ni treba preverjati, le začeti morate ugnezdeno transakcijo. Spodaj v modulu je tam verjetno še popačen z njihovo fiksacijo. To so zagotovljeni hemoroidi.


Približno podobna možnost:


Če je transakcija Active(), potem CommitTransaction() EndIf

podobno: zaveza transakcije s pogojem je čudna. Zakaj je tukaj pogoj? Kaj, lahko je nekdo drug že posnel to transakcijo? Razlog za sojenje.


vzorec:


StartTransaction() While Select.Next() Loop // branje objekta po sklicu // pisanje objekta EndCycle; Izvedi transakcijo();
  1. uvedite nadzorovano zaklepanje, da preprečite zastoj
  2. vnesite klic metode Blokiraj
  3. zaviti v "poskusi", kot je prikazano zgoraj

vzorec:


StartTransaction() Medtem ko Select.Next() Poskus zanke Object.Write(); Poročilo o izjemah ("Pisanje ni uspelo"); EndAttempt; EndCycle; Izvedi transakcijo();

V primeru izjeme ta transakcija ne bo več dokončana. Nima smisla nadaljevati cikla. Kodo je treba prepisati in preveriti prvotno nalogo. Poleg tega zagotovite bolj informativno sporočilo o napaki.

Končno

Kot ste verjetno že uganili, sem eden tistih, ki obožujejo platformo 1C in razvoj na njej. Seveda obstajajo pritožbe glede platforme, zlasti v okolju Highload, a na splošno vam omogoča poceni in hiter razvoj zelo kakovostnih poslovnih aplikacij. Zagotavlja ORM, GUI, spletni vmesnik, poročanje in še veliko več. V komentarjih na Habréju običajno pišejo najrazličnejše arogantne stvari, tako da fantje - glavna težava 1C kot ekosistema ni platforma ali prodajalec. To je prenizek vstopni prag, ki omogoča vstop v panogo ljudem, ki ne razumejo, kaj je računalnik, baza podatkov, odjemalec-strežnik, omrežje in vse to. 1C je preveč olajšal razvoj poslovnih aplikacij. V 20 minutah napišem računovodski sistem za nabavo/prodajo s prilagodljivimi poročili in spletnim odjemalcem. Po tem mi je enostavno pomisliti, da lahko v večjem obsegu pišete na približno enak način. Nekako bo 1C naredil vse interno, ne vem kako, ampak verjetno bo. Naj napišem "StartTransaction()"....

Dodajte oznake