typescript - SQLite - ერთსა და იმავე ტრანზაქციაში მრავალჯერადი გამოძახება
გმადლობთ, რომ შეხედეთ - მე ვწერ ფრონტ ენდის SPA-ს TypeScript-ში. მე ვიყენებ capacitorJS-ს პლატფორმებს შორის თავსებადობისთვის და ვიყენებ @capacitor-community/sqlite პლაგინს. მე ახალბედა ვარ SQLite-ში, მაგრამ არა ბაზებში ზოგადად.
ეს შეიძლება გართულდეს კონკრეტული API-ს გამოყენებით SQLite-ზე.
API აქ არის: https://github.com/capacitor-community/sqlite#supported-methods
რის მნიშვნელობაც არ უნდა ჰქონდე, API არ შეესაბამება ჩემს მოლოდინებს.
მინდა მარტივი მოდელი, რათა შევძლო ტრანზაქციის დაწყება, მრავალი კოლ-ების გაკეთება და საბოლოოდ ტრანზაქციის დადასტურება (ან შეცდომის შემთხვევაში დაბრუნება). შესანიშნავი იქნებოდა, თუ შემეძლებოდა ასევე წაკითხვა იმავე ტრანზაქციის ფარგლებში, ან სულ ცოტა, შემეძლებოდა წაკითხვა ტრანზაქციის გარეთ, როდესაც წერითი ტრანზაქცია ღიაა.
განსხვავდება, რომ ეს (capacitor-community/sqlite) რეპერი ავტომატურად ახორციელებს ტრანზაქციას ყოველი ჩემი გამოძახებისას, მოლოდინით, თუ არ გადავწყვეტ bool პარამეტრით. თუ გადავწყვეტ, პასუხისმგებელი ვარ SQL განაცხადის ბლოკში ტრანზაქციის კოდის ჩასმასზე.
ჩემი პირველი, naivs მიდგომა იყო გამოეცა განცხადება, რომელიც დაიწყებდა ტრანზაქციას, შემდეგ განახორციელებდა დამატებით API გამოძახებებს, რომლებიც უნდა ყოფილიყვნენ ტრანზაქციის ნაწილი, და ბოლოს შეასრულებდა SQL ბრძანებას, რომელიც commit გააკეთებდა ტრანზაქციას.
მაგალითად.
async Transaction(actions: () => Promise<void>): Promise<void> {
await SqliteService.Instance.db.execute('BEGIN TRANSACTION;',
try {
await actions();
await SqliteService.Instance.db.execute('COMMIT TRANSACTION;', false); //useTransaction = false
} catch (e) {
await SqliteService.Instance.db.execute('ROLLBACK TRANSACTION;', false); //useTransaction = false
throw e;
}
ეს საერთოდ არ მუშაობა. ჩანს, რომ მსგავსი მდგომარეობა არ ინარჩუნება ზარების შორის. ვფიქრობ, რომ ზოგი რაღაც (როგორიცაა გახსნილი კურსორი) გამოიწვევს სესიის გახსნას, მაგრამ ჩვეულებრივ სესია უბრალოდ გაიხსნება და დახურვაა ყოველ ზარას API-ისთვის.
მე არ ვცადე ომის ტრიკები, მაგალითად კურსორებთან სამუშაოსთვის ტრანზაქციის გახსენის დასაჭერად, ეს თითქოს ანტიპატერნად გამოიყურებოდა
როდესაც მე ამას ვააზრებდი, ჩანს, რომ შეიძლება მომიწიოს ერთი დიდი SQL ბლოკის გაგზავნა ტრანზაქციის ფარგლებში, რათა SQLite გააკეთოს ის, რაც მინდა.
აპრიბილოდ ვფიქრობ ჩემს documentStore API-ს გადაკეთებაზე, ისე რომ პირდაპირ SQLite-ს დარეკვის ნაცვლად, როდესაც მჭირდებოდა რამდენიმე ოპერაციის გაკეთება ერთ ტრანზაქციაში, შემექმნა sqlBuilder ტიპის კლასი. შემდეგ კი შემეძლებოდა რამდენიმე განცხადების ერთად გაერთიანება.
...
მაგრამ მე მომწონს მიმდინარე ინტერფეისი, და ჩემს documentStore-ზე 'write' მეთოდების გადაწერა რაღაც sqlBuilder-ის მოსაპოვებლად საინტერესო ნაბიჯად მეჩვენება სხვადასხვა მიმართულებით. მაგალითად
async Transaction(sqlBuilder: (builder: WriteSqlBuilder<T>) => {statement: string, values: unknown[]} []) {
...
მინდოდა მცოდნა - როგორ მიდიან ადამიანები ჩვეულებრივ SQLite-ში ერთ ტრანზაქციაში რამდენიმე მოქმედების (კითხვების, წერის) შესრულებაზე?
გმადლობთ!
პასუხი #1
ამიტომ, ეს აღინიშნა როგორც უცნაური ქცევა იმ აპებში, რომელსაც ვიყენებდი capacitor-community/sqlite.
როდესაც დგახართ, რომ აკეთებთ ზარებს, მაგალითად executeSet({sql, params}[], transaction), შეგიძლიათ გადაეცეთ ბულიანი მნიშვნელობა იმისთვის, გამოიყენოთ ტრანზაქცია თუ არა. ეს არის დამხმარე ფუნქცია. ამ transaction მნიშვნელობის ნაგულისხმევი მნიშვნელობა არის true. როდესაც ის დაყენებულია true, დამალული ბიბლიოთეკა ავტომატურად უმატებს BEGIN TRANSACTION და COMMIT TRANSACTION (და ROLLBACK TRANSACTION შეცდომის შემთხვევაში) თქვენს SQL ელემენტებზე, ყველაფერი ერთი ზარის ფარგლებში.
თუ თქვენ კონკრეტულად დააყენებთ transaction-ს false-ზე, ის იმოქმედებს როგორც სტანდარტული SQLite, დაიწყებს სპეციალურ ტრანზაქციას გამოძახებისთვის, და როდესაც გამოძახება დასრულდება, ეს იქნება უკანასკნელი SQL ბრძანება, განსაკუთრებული ტრანზაქცია ავტომატურად დაუმტკიცდება.
ჩემთვის რთული ის იყო, რომ მე ჩემს განვითარების სამუშაოს ვაკეთებ ვებ ბრაუზერში (ამ გადაკვეთის პლატფორმის აპლიკაციისთვის), ამიტომ ვიყენებ jeep-sqlite -ს. jeep-sqlite იყენებს მეხსიერებაში არსებულ SQLite მონაცემთა ბაზას და აქვს saveToStore(dbName) მეთოდი, რომლის დახმარებითაც SQLite ბაიტები ინახება IndexedDB ჩანაწერში.
მგონია, რომ რაც ხდება ის არის, რომ მე ვაკეთებდი ფლაშინგს ტრანზაქციის შუაში. ფლაშინგის შემდეგ აღარ იყო აქტიური ტრანზაქცია.
ბოლო მოხდენაში, მე ვიყენებ async-lock-ს ჩემს წვდომაზე SQLite DB wrapper-ზე, და მაქვს საკუთარი async Transaction(actions:() => Promise<void>) მეთოდი, რომელიც თავის მხრივ მართავს BEGIN/COMMIT/ROLLBACK-ს, ასევე რამდენიმე ზოგადი მიზნების DocumentStore მეთოდი, რომლებიც ქმნიან ფრაგმენტებს, რომლებიც თვითმატურად შედიან ტრანზაქციაში.