Чаро транзаксияҳо лозиманд
Бисёр вақт ҳангоми кор бо базаи маълумот чунин ҳолат мешавад, ки бояд бисёр амалҳои гуногун иҷро шавад, аммо маънои онон танҳо дар якҷоягӣ аст.
Масалан, мо барномаи бонкӣ менависем, ки бояд се амалро иҷро кунад:
- Аз ҳисоби мизоҷ маблағ кашидан
- Ба ҳисоби қабулкунанда маблағ илова кардан
- Маълумот дар бораи гузаришро ба "ҷурнал" сабт кардан
Агар ҳангоми иҷрои ягон аз ин амалҳо хато шавад, пас ду таҳтиқимро низ бояд бекор кард. Оё мумкин аст, ки аз мизоҷ маблағ кашида шавад, аммо ба қабулкунанда иловакунӣ нашавад? Ё ба қабулкунанда иловакунӣ шавад, аммо аз мизоҷ накашонда шуд?
Ҳамин тавр, чунин гурӯҳбандии мантиқии амалҳои гуногун дар як ҷо транзаксия ном дорад. Ба ибораи дигар, транзаксия — гурӯҳи амалҳо, ки бояд танҳо якҷоя иҷро шаванд. Агар ягон амалиёт иҷро нашавад ё бо хатоги иҷро шавад, пас ҳамаи амалҳои дигар бояд бекор шаванд.
Транзаксия одатан се ҳолат дорад:
- initial state — ҳолати система пеш аз иҷрои гурӯҳи амалҳо
- success state — ҳолат пас аз иҷрои гурӯҳи амалҳо
- failed state — ягон мушкилот пайдо шуд

Дар ин ҳолат одатан се фармон мавҷуд аст:
- begin/start — пеш аз оғози гурӯҳи мантиқии амалҳо иҷро карда мешавад
- commit — пас аз гурӯҳи амалҳои транзаксия иҷро карда мешавад
- rollback — системаро аз failed state ба initial state бозмегардонад
Ин тавр кор мекунад.
Аввалан, лозим аст, ки транзаксия кушода шавад — бо фармони begin() ё start(). Даъвати ин фармон ҳолати системаро нишон медиҳад, ки ба он кӯшиш мекунем бозгардем, агар чизе хато шавад.
Он гоҳ ҳамаи амалҳо, ки дар гурӯҳи мантиқӣ будаанд, иҷро карда мешаванд — транзаксия.
Он гоҳ фармони commit() даъват мешавад. Даъвати он охири гурӯҳи мантиқии амалҳоро нишон дода, одатан раванди иҷрои ин амалҳоро дар амал оғоз мекунад.
Ёдовар шудан лозим аст, ки мо чизе дар FileWriter менавиштем: аввал ҳамаи чизҳое, ки мо навиштем, дар хотира нигоҳ дошта мешавад, пас ҳангоми даъвати фармони flush() ҳамаи маълумоти аз буфер дар хотира ба диск менависанд. Ин flush() — ин ҳамон commit транзаксия аст.
Ва агар ҳангоми кори транзаксия хато пайдо шавад, пас лозим аст, ки раванд барои бозгашт ба ҳолати оғозӣ оғоз карда шавад. Ин раванд rollback() ном дорад, ва барои он одатан методи ҳамном масъул аст.
Дар маҷмӯъ, ду роҳи анҷом додани транзаксия вуҷуд дорад:
- COMMIT — ҳамаи тағйиротҳои воридшуда тасдиқ мекунем
- ROLLBACK — ҳамаи тағйиротҳои воридшуда бекор мекунем
Транзаксияҳо дар JDBC
Қариб ҳар як СУБД метавонад бо транзаксияҳо кор кунад. Пас, дар JDBC низ дастгирии ин кор ҳаст. Ҳама чиз хеле осон амалӣ шудааст.
Аввалан, ҳар як даъвати методи execute() объекти Statement дар транзаксияи алоҳида иҷро карда мешавад. Барои ин, Connection параметри AutoCommit дорад. Агар он дар true бошад, пас commit() пас аз ҳар як даъвати методи execute() даъват мешавад.
Дувум, агар хоҳед, ки якчанд амрҳоро дар як транзаксия иҷро кунед, пас онро ин тавр иҷро кардан мумкин аст:
- AutoCommit-ро хомӯш мекунем
- амрҳои худро даъват мекунем
- методи commit() ро қатъиян даъват мекунем
Ин хеле содда ба назар мерасад:
connection.setAutoCommit(false);
Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
connection.commit();
Агар ҳангоми кори методи commit() дар сервер хато шавад, пас SQL-сервер ҳамаи се амалиётро бекор мекунад.
Аммо ҳолатҳое мешаванд, ки хатогӣ дар тарафи муштарӣ пайдо мешавад, ва мо ҳанӯз ба даъвати методи commit() нарасидаем:
connection.setAutoCommit(false);
Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE чанд хатогиҳо ба истисно меоваранд");
connection.commit();
Агар ҳангоми кори яке аз executeUpdate() хатогӣ шавад, пас методи commit() даъват намешавад. Барои бекор кардани ҳамаи амалҳои анҷомшуда, бояд методи rollback() даъват карда шавад. Одатан ин чунин ба назар мерасад:
try{
connection.setAutoCommit(false);
Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount3 = statement.executeUpdate("UPDATE чанд хатогиҳо ба истисно меоваранд");
connection.commit();
}
catch (Exception e) {
connection.rollback();
}
Нуқтаҳои ҳифз
Бо пайдоиши JDBC 3.0 имконияти самараноктар кор кардан бо бекори транзаксия пайдо шуд. Ҳоло мумкин аст нуқтаҳои ҳифз — save points гузошта шаванд, ва ҳангоми даъвати амалиёти rollback() ба нуқтаи махсуси ҳифз бозгардем.
Барои ҳифз кардани худ, бояд як нуқтаи ҳифзӣ сохта шавад, ин тариқи фармони зерин анҷом дода мешавад:
Savepoint save = connection.setSavepoint();
Бозгашт ба нуқтаи ҳифз бо фармони зерин анҷом дода мешавад:
connection.rollback(save);
Биёед кӯшиш кунем, ки нуқтаи ҳифзро пеш аз фармони проблемавии мо илова кунем:
try{
connection.setAutoCommit(false);
Statement statement = connection.createStatement();
int rowsCount1 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
int rowsCount2 = statement.executeUpdate("UPDATE employee SET salary = salary+1000");
Savepoint save = connection.setSavepoint();
try{
int rowsCount3 = statement.executeUpdate("UPDATE чанд хатогиҳо ба истисно меоваранд");
}
catch (Exception e) {
connection.rollback(save);
}
connection.commit();
}
catch (Exception e) {
connection.rollback();
}
Мо тавре, ки гӯё транзаксияҳои дохилӣ ташкил кардем, бо илова кардани save-point пеш аз даъвати методи проблемавӣ ва бозгашт ба ҳолати ҳифзшуда бо даъвати методи rollback(save).
Бале, ин ба save/load дар бозиҳо хеле монанд аст.
GO TO FULL VERSION