Տրանզակցիաներ
Drupal-ն նույնպես աջակցում է տրանզակցիաներին՝ ներառյալ թափանցիկ պահուստային տարբերակ այն տվյալների բազաների համար, որոնք չեն աջակցում տրանզակցիաներին։ Սակայն տրանզակցիաները կարող են բավական բարդ լինել, եթե փորձեք միաժամանակ գործարկել երկու տրանզակցիա։ Այս դեպքի վարքը կախված է տվյալների բազայի տեսակից։
Նման խնդիր գոյություն ունի նաև C/C++ լեզուներում՝ դրսի կողպեքների հետ։ Եթե կոդը արդեն ձեռք է բերել A կողպեքը և փորձի կրկին ձեռք բերել նույն A կողպեքը, կոդը կկանգնի (deadlock): Եթե դուք գրում եք կոդ, որը ստուգում է, արդյոք արդեն ունի կողպեքը և չի փորձում այն կրկին ստանալ, ապա խուսափում եք deadlock-ից, բայց կարող եք նախկինում բացել կողպեքը։
SQL-ում նույն խնդիրը կա։ Եթե ձեր կոդը արդեն գտնվում է տրանզակցիայի մեջ, նոր տրանզակցիայի մեկնարկը անսպասելի և տխուր հետևանք ունի՝ ընթացիկ տրանզակցիայի կոմիտացում և նորի մեկնարկ։
Java-ն լուծում է կողպեքների ներդաշնակության խնդիրը իր կողպեքների միջոցով՝ իրականացնելով ներդաշնակության մակարդակի կառուցվածքի աջակցություն, որը նման է ստորև ներկայացվածին։ Java-ն թույլ է տալիս նշել ֆունկցիաները որպես «synchronized», ինչը заставляет ֆունկցիան սպասել կողպեքը ստանալուն մինչ մեկնարկը և բաց թողնել այն, երբ այն այլևս անհրաժեշտ չէ։ Եթե մեկ synchronized ֆունկցիա կանչում է մյուսը նույն դասում, Java-ն հաշվում է կողպեքի ներդաշնակությունը։ Արտաքին ֆունկցիան ստանում է կողպեքը, ներքինը չի անում կողպեքի գործողություններ, իսկ արտաքին ֆունկցիան բաց է թողնում կողպեքը վերադարձի ժամանակ։
Թեև PHP-ում չենք կարող հայտարարել ֆունկցիաներ որպես «transactional», մենք կարող ենք էմուլացնել Java-ի ներդաշնակության տրամաբանությունը՝ օգտագործելով օբյեկտներ՝ կոնստրուկտորներով և դեստրուկտորներով։ Ֆունկցիան պարզապես կանչում է «$transaction = $connection->startTransaction()» որպես առաջին (կամ գրեթե առաջին) գործողություն՝ ինքն իրեն դարձնելով transactional։ Եթե մի transactional ֆունկցիա կանչում է մյուսը, մեր տրանզակցիայի ընդլայնման մակարդակը ներառում է դրանք՝ չկատարելով transactional գործողություններ (օրինակ՝ տվյալների բազայի տեսանկյունից) ներքին մակարդակներում։
Նոր տրանզակցիա սկսելու համար պարզապես կանչեք $transaction = $connection->startTransaction(); ձեր սեփական կոդում։ Տրանզակցիան բաց կմնա այնքան ժամանակ, որքան փոփոխականը $transaction առկա է տեսանելիության մեջ։ Երբ $transaction ոչնչացվի, տրանզակցիան կնքվի։ Եթե ձեր տրանզակցիան ներառված է մեկ այլ տրանզակցիայի մեջ, Drupal-ը կգրանցի յուրաքանչյուր տրանզակցիա և կնքի ամենաուրսի տրանզակցիան միայն այն ժամանակ, երբ վերջին տրանզակցիայի օբյեկտը դուրս գա տեսանելիությունից, այսինքն՝ բոլոր համապատասխան հարցումները հաջողությամբ ավարտվեն։
Դուք պետք է վերագրեք $connection->startTransaction(); վերադարձվող արժեքը փոփոխականին, ինչպես օրինակ։ Եթե կանչեք մեթոդը առանց վերագրելու վերադարձվող արժեքը, ձեր տրանզակցիան անմիջապես կնքվի, ինչը անիմաստ կդարձնի այն։
Տրանզակցիայի ռոլբեքը կառավարում է կոնեկտորի օբյեկտը ($connection->rollBack()) Drupal 8-ում, բայց սովորաբար պետք է կատարվի տրանզակցիայի ծածկույթի մեթոդով ($action->rollBack())։ Ռոլբեքը պետք է կատարվի transaction-ի մեթոդով, քանի որ այն ռոլբեքում է հենց տվյալ transaction-ը՝ օգտագործելով նրա անունը, որտեղ $connection->rollBack() որպես ստանդարտ սահմանում ունի անունը drupal_transaction և կարող է չհամապատասխանող արդյունքներ տալ, եթե օգտագործվի ներդրված տրանզակցիաների հետ։
Օրինակ:
function my_transaction_function() {
// Տրանզակցիան սկսվում է այստեղ։
$transaction = $connection->startTransaction();
try {
$id = $connection->insert('example')
->fields([
'field1' => 'mystring',
'field2' => 5,
])
->execute();
my_other_function($id);
return $id;
}
catch (Exception $e) {
$transaction->rollBack();
watchdog_exception('my_type', $e);
}
// Կարելի է թողնել $transaction-ը դուրս տեսանելիությունից,
// և տրանզակցիան ավտոմատ կնքվի, եթե այն դեռ չի արվել ռոլբեք։
// Սակայն եթե ունեք հավելյալ աշխատանք, պետք է ինքներդ ձեռքով կոմիտեք տրանզակցիան։
$transaction->commit();
// Ավելին կոդը, որը գտնվում է տրանզակցիայի դրսում։
}
function my_other_function($id) {
// Տրանզակցիան դեռ բաց է այստեղ։
if ($id % 2 == 0) {
$connection->update('example')
->condition('id', $id)
->fields(['field2' => 10])
->execute();
}
}