Bakit kailangan ang mga transaksyon

Kadalasan, kapag nagtatrabaho sa isang database, lumitaw ang isang sitwasyon kung kailan kailangan mong magsagawa ng maraming iba't ibang mga aksyon, ngunit magkakasama lamang ang mga ito.

Halimbawa, sumusulat kami ng software sa pagbabangko na dapat gumawa ng tatlong bagay:

  • Mag-withdraw ng pera mula sa account ng customer
  • Magdagdag ng pera sa account ng tatanggap
  • Itala ang data ng pag-post sa "log ng pag-post"

Kung may naganap na error sa panahon ng pagpapatupad ng alinman sa mga pagkilos na ito, dapat ding kanselahin ang dalawa pa. Imposibleng isulat ang pera mula sa kliyente at hindi idagdag ito sa tatanggap? Well, o idagdag sa tatanggap, ngunit hindi isulat mula sa kliyente?

Kaya, ang ganitong lohikal na pagpapangkat ng iba't ibang mga aksyon sa isa ay tinatawag na isang transaksyon . Sa madaling salita, ang isang transaksyon ay isang pangkat ng mga aksyon na dapat isagawa lamang nang sama-sama . Kung ang anumang pagkilos ay nabigo o naisakatuparan nang may error, dapat na kanselahin ang lahat ng iba pang pagkilos.

Ang isang transaksyon ay karaniwang may tatlong estado:

  • paunang estado - ang estado ng system bago isagawa ang isang pangkat ng mga aksyon
  • katayuan ng tagumpay - estado pagkatapos makumpleto ang pangkat ng pagkilos
  • nabigong estado - may nangyaring mali

Sa kasong ito, karaniwang mayroong tatlong utos:

  • begin/start - naisakatuparan bago magsimula ang lohikal na pangkat ng mga aksyon
  • commit - isinagawa pagkatapos ng pangkat ng pagkilos ng transaksyon
  • rollback - sinisimulan ang proseso ng pagbabalik ng system mula sa nabigong estado sa paunang estado

Ito ay gumagana tulad nito.

Una kailangan mong magbukas ng transaksyon - tawagan ang begin() o start() method . Ang pagtawag sa paraang ito ay nagpapahiwatig ng estado ng system kung saan susubukan naming bumalik kung may mali.

Pagkatapos ang lahat ng mga aksyon ay ginanap, na pinagsama sa isang lohikal na grupo - isang transaksyon.

Pagkatapos ang commit() na pamamaraan ay tinatawag na . Ang tawag nito ay nagmamarka ng pagtatapos ng isang lohikal na pangkat ng mga aksyon, at karaniwan ding nagsisimula sa proseso ng pagsasabuhay ng mga pagkilos na ito.

Alalahanin kung paano namin isinulat ang isang bagay sa FileWriter: una, lahat ng aming isinulat ay naka-imbak sa memorya, at pagkatapos ay kapag ang flush () na pamamaraan ay tinatawag na , ang lahat ng data mula sa buffer sa memorya ay nakasulat sa disk. Ang flush() na ito ay ang transaction commit.

Well, kung ang isang error ay naganap sa panahon ng operasyon ng transaksyon, pagkatapos ay kailangan mong simulan ang proseso ng pagbabalik sa panimulang estado. Ang prosesong ito ay tinatawag na rollback() , at ang pamamaraan ng parehong pangalan ay karaniwang responsable para dito.

Sa halos pagsasalita, mayroong 2 paraan upang makumpleto ang isang transaksyon:

  • COMMIT - kinukumpirma namin ang lahat ng mga pagbabagong ginawa
  • ROLLBACK - ibalik ang lahat ng ginawang pagbabago

Mga transaksyon sa JDBC

Halos bawat DBMS ay maaaring gumana sa mga transaksyon. Kaya may suporta rin ang JDBC para sa kasong ito. Ang lahat ay ipinatupad nang napakasimple.

Una, ang bawat tawag sa execute() method ng Statement object ay isinasagawa sa isang hiwalay na transaksyon. Upang gawin ito, ang Koneksyon ay may parameter na AutoCommit . Kung ito ay nakatakda sa true , pagkatapos ay tatawagin ang commit() pagkatapos ng bawat tawag sa execute() method .

Pangalawa, kung nais mong magsagawa ng ilang mga utos sa isang transaksyon, maaari mo itong gawin tulad nito:

  • huwag paganahin ang AutoCommit
  • pagtawag sa ating mga utos
  • tawagan ang commit() na paraan nang tahasan

Mukhang napakasimple:

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();

Kung may naganap na error sa server habang tumatakbo ang commit() method , kakanselahin ng SQL server ang lahat ng tatlong aksyon.

Ngunit may mga sitwasyon kung kailan nangyayari pa rin ang error sa panig ng kliyente, at hindi na kami nakarating sa commit() method call :

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 multiple typos will result in an exception");

connection.commit();

Kung may naganap na error sa panahon ng pagpapatupad ng isang executeUpdate() , hindi tatawagin ang commit() na paraan. Upang ibalik ang lahat ng ginawang pagkilos, kailangan mong tawagan ang rollback() na paraan . Karaniwang ganito ang hitsura:

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 multiple typos will result in an exception");

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

Savepoints

Sa pagdating ng JDBC 3.0, naging posible na gumana nang mas mahusay sa rollback ng transaksyon. Ngayon ay maaari ka nang magtakda ng mga save point - mag-save ng mga puntos, at kapag tinawag mo ang rollback () operation , roll back sa isang partikular na save point.

Upang makatipid, kailangan mong lumikha ng isang savepoint, ginagawa ito gamit ang utos:

Savepoint save = connection.setSavepoint();

Ang pagbabalik sa isang savepoint ay ginagawa gamit ang utos:

connection.rollback(save);

Subukan nating magdagdag ng savepoint bago ang ating problemadong command:

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 multiple typos will result in an exception");
 	 }
 	 catch (Exception e) {
    	   connection.rollback(save);
 	 }

	  connection.commit();
 }
 catch (Exception e) {
   connection.rollback();
}

Inayos namin ang mga nested na transaksyon sa pamamagitan ng pagdaragdag ng save-point bago tawagan ang may problemang paraan, at bumalik sa naka-save na estado sa pamamagitan ng pagtawag sa rollback(save) na paraan .

Oo, ito ay halos kapareho sa pag-save/pag-load sa mga laro.