เหตุใดจึงต้องทำธุรกรรม
บ่อยครั้ง เมื่อทำงานกับฐานข้อมูล สถานการณ์เกิดขึ้นเมื่อคุณจำเป็นต้องดำเนินการต่างๆ มากมาย แต่การกระทำเหล่านี้สมเหตุสมผลร่วมกันเท่านั้น
ตัวอย่างเช่น เรากำลังเขียนซอฟต์แวร์ธนาคารที่ควรทำสามสิ่ง:
- ถอนเงินจากบัญชีของลูกค้า
- เพิ่มเงินในบัญชีของผู้รับ
- บันทึกข้อมูลการผ่านรายการใน “บันทึกการผ่านรายการ”
หากเกิดข้อผิดพลาดระหว่างการดำเนินการใด ๆ เหล่านี้ จะต้องยกเลิกอีกสองรายการด้วย เป็นไปไม่ได้ที่จะตัดเงินจากลูกค้าและไม่เพิ่มไปยังผู้รับ? หรือเพิ่มไปยังผู้รับ แต่ไม่ตัดออกจากลูกค้า
ดังนั้นการจัดกลุ่มเชิงตรรกะของการกระทำที่แตกต่างกันให้เป็นรายการเดียวจึงเรียกว่าธุรกรรม . กล่าวอีกนัยหนึ่ง ธุรกรรมคือกลุ่มของการกระทำที่ต้องดำเนินการทั้งหมดพร้อมกันเท่านั้น หากการดำเนินการใดๆ ล้มเหลวหรือดำเนินการโดยมีข้อผิดพลาด การดำเนินการอื่นๆ ทั้งหมดจะต้องถูกยกเลิก
การทำธุรกรรมมักจะมีสามสถานะ:
- สถานะเริ่มต้น - สถานะของระบบก่อนดำเนินการกลุ่มของการกระทำ
- สถานะสำเร็จ - สถานะหลังจากการดำเนินการกลุ่มเสร็จสิ้น
- สถานะล้มเหลว - มีบางอย่างผิดพลาด
ในกรณีนี้ มักจะมีสามคำสั่ง:
- เริ่มต้น/เริ่ม - ดำเนินการก่อนเริ่มกลุ่มการกระทำแบบลอจิคัล
- กระทำ - ดำเนินการหลังจากกลุ่มการกระทำธุรกรรม
- ย้อนกลับ - เริ่มกระบวนการคืนระบบจากสถานะล้มเหลวเป็นสถานะเริ่มต้น
มันใช้งานได้เช่นนี้
ก่อนอื่นคุณต้องเปิดธุรกรรม - เรียกใช้เมธอด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();
}
เราจัดระเบียบธุรกรรมที่ซ้อนกันโดยเพิ่มจุดบันทึกก่อนที่จะเรียกใช้เมธอดที่มีปัญหา และกลับสู่สถานะที่บันทึกไว้โดยเรียกเมธอด ย้อน กลับ(บันทึก)
ใช่ มันคล้ายกับการบันทึก/โหลดในเกมมาก