Databases
Nipprevjenu Dejta Inkonsistenti bl-ACID Transactions
Kull proprjetà tal-ACID għandha default, u tlieta minnhom iwiegħdu inqas milli tgħid il-kelma. Ir-raba' default huwa onest, u hemmhekk qiegħed il-periklu.
Li tgeżwer ix-xogħol tiegħek f'transaction iġġiegħlek tħossok qisek xtrajt assigurazzjoni. Tikteb BEGIN, tikteb COMMIT, u l-erba' proprjetajiet tal-ACID suppost jieħdu ħsieb il-bqija.
Jieħdu ħsieb, imma biss sakemm jaslu s-settings li writt. Atomicity, Consistency, Isolation u Durability kull waħda tasal b'default, u tliet defaults minnhom iwasslu bil-kwiet inqas milli tissuġġerixxi l-kelma. Hawn fejn jieqaf kull wieħed.
Atomicity tieqaf mal-ewwel żball li tiddeċiedi li tinjora
Atomicity hija kollox jew xejn, u s-sorpriża qiegħda f'dak li jgħodd bħala żball li jistħoqqlu abort.
Fuq SQL Server, XACT_ABORT huwa OFF bħala default fit-T-SQL. B'dan mitfi, żball waqt l-eżekuzzjoni ġewwa transaction espliċita jista' jħassar biss l-istatement li falla u jħalli l-eżekuzzjoni tkompli. It-transaction tibqa' miftuħa. Jekk il-linja ta' wara tkun COMMIT, tikkommetti nofs ix-xogħol u d-database jirrapporta suċċess.
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 100 WHERE Id = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE Id = 999; -- jikser constraint
COMMIT; -- b'XACT_ABORT OFF, dan xorta jista' jikkommetti d-debitu
Linja waħda ssolviha, u postha fil-bidu ta' kull ħaġa li tikteb fuq diversi statements:
SET XACT_ABORT ON;
Issa kull żball waqt l-eżekuzzjoni jtemm it-transaction kollha u jagħmel rollback. Fil-.NET dan jgħodd inqas jekk tħalli lil EF Core ikun sid l-unità tax-xogħol, għax sejħa waħda ta' SaveChangesAsync diġà tiġi mgeżwra f'transaction li tħassar kollox flimkien. In-nasba hemm hija li taqsam operazzjoni waħda tan-negozju f'żewġ sejħiet ta' SaveChangesAsync: dawk huma żewġ transactions, u l-ispazju bejniethom huwa tieqa fejn nofs ix-xogħol huwa durable u n-nofs l-ieħor qatt ma ġara.
Consistency tinforza biss dak li ktibt
Din hija l-proprjetà li n-nies l-aktar jassumu li hija awtomatika. Mhijiex awtomatika xejn.
Consistency tiggarantixxi li transaction iċċaqlaq id-database minn stat validu għal ieħor, fejn validu jfisser il-constraints li ddikjarajt. Primary keys, foreign keys, unique indexes, CHECK, NOT NULL. Il-lista hija dik kollha. Id-database qatt ma sema' bir-regoli tan-negozju tiegħek.
Mela regola bħal "it-total ta' ordni qatt ma jkun negattiv" li tgħix f'guard clause bil-C# mhijiex garanzija tad-database. Iżżomm eżattament sakemm kull kitba tgħaddi minn dik il-klassi, u dan jieqaf ikun veru l-ewwel darba li xi ħadd iħaddem script ta' migration, importazzjoni bl-ingrossa, jew tieni servizz fuq l-istess tabella.
ALTER TABLE Orders
ADD CONSTRAINT CK_Orders_Total_Positive CHECK (Total > 0);
Jew iddikjarata f'EF Core, biex tivvjaġġa mal-migration minflok tgħix f'runbook:
builder.ToTable(t => t.HasCheckConstraint("CK_Orders_Total_Positive", "Total > 0"));
Atomicity u Isolation huma mġiba li tieħu mill-engine. Consistency hija proprjetà tal-schema tiegħek, u schema vojta ma twiegħed xejn.
Isolation tibda f'livell li xorta jitlef kitbiet
SQL Server jaħdem f'READ COMMITTED sakemm ma tgħidlux mod ieħor. Dan iwaqqfek milli taqra dejta mhux committed, u n-nies raġonevolment jisimgħu "committed" bħala "sikur".
Jerħi s-shared locks hekk kif kull statement jispiċċa, allura ma jgħid xejn dwar l-ispazju bejn il-qari u l-kitba tiegħek:
Session A: SELECT Balance FROM Accounts WHERE Id = 1; -- jaqra 100
Session B: SELECT Balance FROM Accounts WHERE Id = 1; -- jaqra 100
Session A: UPDATE Accounts SET Balance = 50 WHERE Id = 1;
Session B: UPDATE Accounts SET Balance = 50 WHERE Id = 1; -- il-kitba ta' A sparixxiet
Iż-żewġ transactions kienu validi għalihom infushom. Flimkien, tilfu update. Li tkun ġewwa transaction u li tkun sikur minn kitbiet konkorrenti huma garanziji separati, u d-default jagħtik biss l-ewwel waħda.
Il-fix tas-soltu mhuwiex livell ta' isolation aktar strett, li jiswa konkorrenza kullimkien biex isolvi problema f'post wieħed. Hija kolonna ta' verżjoni, biex it-tieni kitba tfalli b'leħen għoli minflok tirbaħ fis-skiet:
[Timestamp]
public byte[] RowVersion { get; set; } = [];
EF Core imbagħad iżid WHERE RowVersion = @original mal-update, u jitfa' DbUpdateConcurrencyException meta ebda ringiela ma taqbel.
Durability għandha d-default onest, u hemm qiegħda l-problema
Durability hija l-eċċezzjoni. Id-default tagħha huwa korrett: SQL Server juża write-ahead logging, il-log record jasal fl-istorage durable qabel ma l-commit jiġi kkonfermat, u crash jerġa' jindaqq waqt l-irkupru. COMMIT ifisser dak li taħseb li jfisser.
U propju għalhekk ħadd ma jiċċekkja. Minn SQL Server 2014 tista' tinnegozjah:
ALTER DATABASE AppDb SET DELAYED_DURABILITY = FORCED;
Issa COMMIT jirritorna hekk kif il-log record ikun fil-memorja u l-flush isir f'lottijiet. Tixtri throughput veru fuq workloads tqal fil-kitba, u tħallasha b'tieqa fejn transactions li l-applikazzjoni ntqalilha li kienu committed jisparixxu f'qatgħa tad-dawl.
Jasal DISABLED, allura ħadd ma jixgħelu b'aċċident. Imma huwa fix plawżibbli għal konġestjoni fil-log, applikat fil-livell tad-database, inviżibbli mill-applikazzjoni. Kull żviluppatur 'il fuq minn dik il-bidla jibqa' jemmen li COMMIT ifisser dak li kien ifisser qabel.
Il-verżjoni qasira
It-transactions jistħoqqilhom, u d-defaults fil-biċċa l-kbira huma raġonevoli. Sempliċement mhumiex il-garanziji li jissuġġerixxu l-erba' kelmiet.
Ixgħel XACT_ABORT għal kitbiet fuq diversi statements. Poġġi l-invarjanti tiegħek fl-schema, għax huwa l-uniku post fejn consistency tiġi infurzata. Assumi li l-livell ta' isolation default se jitlef kitba konkorrenti u żid kolonna ta' verżjoni fejn dan jgħodd. U ittratta durability bħala setting li xi ħadd jista' jbiddel, mhux bħala liġi tad-database.