เหตุใดจึงต้องทำธุรกรรม

บ่อยครั้ง เมื่อทำงานกับฐานข้อมูล สถานการณ์เกิดขึ้นเมื่อคุณจำเป็นต้องดำเนินการต่างๆ มากมาย แต่การกระทำเหล่านี้สมเหตุสมผลร่วมกันเท่านั้น

ตัวอย่างเช่น เรากำลังเขียนซอฟต์แวร์ธนาคารที่ควรทำสามสิ่ง:

  • ถอนเงินจากบัญชีของลูกค้า
  • เพิ่มเงินในบัญชีของผู้รับ
  • บันทึกข้อมูลการผ่านรายการใน “บันทึกการผ่านรายการ”

หากเกิดข้อผิดพลาดระหว่างการดำเนินการใด ๆ เหล่านี้ จะต้องยกเลิกอีกสองรายการด้วย เป็นไปไม่ได้ที่จะตัดเงินจากลูกค้าและไม่เพิ่มไปยังผู้รับ? หรือเพิ่มไปยังผู้รับ แต่ไม่ตัดออกจากลูกค้า

ดังนั้นการจัดกลุ่มเชิงตรรกะของการกระทำที่แตกต่างกันให้เป็นรายการเดียวจึงเรียกว่าธุรกรรม . กล่าวอีกนัยหนึ่ง ธุรกรรมคือกลุ่มของการกระทำที่ต้องดำเนินการทั้งหมดพร้อมกันเท่านั้น หากการดำเนินการใดๆ ล้มเหลวหรือดำเนินการโดยมีข้อผิดพลาด การดำเนินการอื่นๆ ทั้งหมดจะต้องถูกยกเลิก

การทำธุรกรรมมักจะมีสามสถานะ:

  • สถานะเริ่มต้น - สถานะของระบบก่อนดำเนินการกลุ่มของการกระทำ
  • สถานะสำเร็จ - สถานะหลังจากการดำเนินการกลุ่มเสร็จสิ้น
  • สถานะล้มเหลว - มีบางอย่างผิดพลาด

ในกรณีนี้ มักจะมีสามคำสั่ง:

  • เริ่มต้น/เริ่ม - ดำเนินการก่อนเริ่มกลุ่มการกระทำแบบลอจิคัล
  • กระทำ - ดำเนินการหลังจากกลุ่มการกระทำธุรกรรม
  • ย้อนกลับ - เริ่มกระบวนการคืนระบบจากสถานะล้มเหลวเป็นสถานะเริ่มต้น

มันใช้งานได้เช่นนี้

ก่อนอื่นคุณต้องเปิดธุรกรรม - เรียกใช้เมธอดstart()หรือstart () การเรียกเมธอดนี้เป็นการระบุสถานะของระบบที่เราจะพยายามส่งคืนหากมีสิ่งผิดปกติเกิดขึ้น

จากนั้นดำเนินการทั้งหมดซึ่งรวมกันเป็นกลุ่มตรรกะ - ธุรกรรม

จากนั้นจึงเรียก เมธอด commit() การเรียกใช้เป็นการสิ้นสุดกลุ่มของการกระทำแบบลอจิคัล และมักจะเริ่มกระบวนการนำการกระทำเหล่านี้ไปใช้จริง

จำวิธีที่เราเขียนบางอย่างใน FileWriter: อันดับแรก ทุกสิ่งที่เราเขียนจะถูกจัดเก็บไว้ในหน่วยความจำ จากนั้นเมื่อเรียก ใช้เมธอด flush ()ข้อมูลทั้งหมดจากบัฟเฟอร์ในหน่วยความจำจะถูกเขียนลงดิสก์ flush()นี้เป็นธุรกรรมที่กระทำ

หากเกิดข้อผิดพลาดระหว่างการทำธุรกรรมคุณต้องเริ่มกระบวนการกลับสู่สถานะเริ่มต้น กระบวนการนี้เรียกว่าการย้อนกลับ ()และวิธีการที่มีชื่อเดียวกันมักจะรับผิดชอบ

พูดคร่าวๆ มี 2 วิธีในการทำธุรกรรม:

  • COMMIT - เรายืนยันการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้น
  • ย้อนกลับ - ย้อนกลับการเปลี่ยนแปลงทั้งหมดที่ทำ

ธุรกรรมใน JDBC

DBMS เกือบทุกตัวสามารถทำงานกับธุรกรรมได้ ดังนั้น JDBC จึงสนับสนุนกรณีนี้ด้วย ทุกอย่างถูกนำไปใช้อย่างเรียบง่าย

ขั้นแรก การเรียกใช้เมธอด execute()ของวัตถุ Statement แต่ละครั้ง จะถูกดำเนินการในธุรกรรมแยกต่างหาก ในการทำเช่น นี้Connection มี พารามิเตอร์ AutoCommit หากตั้งค่าเป็นtrue แล้ว commit ()จะถูกเรียกหลังจากการเรียกใช้เมธอดexecute() แต่ละครั้ง

ประการที่สอง หากคุณต้องการดำเนินการหลายคำสั่งในธุรกรรมเดียว คุณสามารถทำได้ดังนี้:

  • ปิดใช้งานการคอมมิตอัตโนมัติ
  • เรียกคำสั่งของเรา
  • เรียก วิธี การ 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();

หากเกิดข้อผิดพลาดบนเซิร์ฟเวอร์ในขณะที่คอมมิต()เมธอดกำลังทำงาน เซิร์ฟเวอร์ 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 multiple typos will result in an exception");

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

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

จุดเซฟ

ด้วยการถือกำเนิดของ JDBC 3.0 ทำให้สามารถทำงานได้อย่างมีประสิทธิภาพมากขึ้นด้วยการย้อนกลับธุรกรรม ตอนนี้คุณสามารถตั้งค่าจุดบันทึก - จุดบันทึก และเมื่อคุณเรียก ใช้การดำเนินการ ย้อนกลับ ()ให้ย้อนกลับไปยังจุดบันทึกเฉพาะ

ในการบันทึก คุณต้องสร้างจุดเซฟ ซึ่งทำได้โดยใช้คำสั่ง:

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

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

เราจัดระเบียบธุรกรรมที่ซ้อนกันโดยเพิ่มจุดบันทึกก่อนที่จะเรียกใช้เมธอดที่มีปัญหา และกลับสู่สถานะที่บันทึกไว้โดยเรียกเมธอด ย้อน กลับ(บันทึก)

ใช่ มันคล้ายกับการบันทึก/โหลดในเกมมาก