Disabling Auto-Commit Mode
เมื่อทำการสร้าง connection นั้น จะอยู่ในโหมด Auto Commit โดยอัตโนมัติ นั่นหมายถึงว่าแต่ละคำสั่ง SQL ที่กระทำ transaction นั้นจะ Commit(ยืนยัน) หมด(ถ้าจะให้ละเอียดคือ ในคำสั่ง SQL นั้นจะ Commit เมื่อมันเสร็จสิ้นแล้ว ไม่ใช่ในขณะทำงาน(excuted) )
ในการ disable commit คือ con.setAutoCommit(false);
หลังจากที่เราได้ทำการ disable commit ไปแล้วจะไม่มีคำสั่ง SQL Statement ไหน commit จนกว่าเราจะใช้คำสั่ง commit เอง คำสั่ง SQL ทั้งหมดจะถูก excute หลังจากเรียกคำสั่ง commit คือเพิ่มเข้าไปใน transection ปัจจุบันและ commit รวมกันเป็นกลุ่ม ดังตัวอย่าง
public void updateCoffeeSales(HashMapsalesForWeek) throws SQLException { PreparedStatement updateSales = null; PreparedStatement updateTotal = null; String updateString = "update " + dbName + ".COFFEES " + "set SALES = ? where COF_NAME = ?"; String updateStatement = "update " + dbName + ".COFFEES " + "set TOTAL = TOTAL + ? " + "where COF_NAME = ?"; try { con.setAutoCommit(false); updateSales = con.prepareStatement(updateString); updateTotal = con.prepareStatement(updateStatement); for (Map.Entry e : salesForWeek.entrySet()) { updateSales.setInt(1, e.getValue().intValue()); updateSales.setString(2, e.getKey()); updateSales.executeUpdate(); updateTotal.setInt(1, e.getValue().intValue()); updateTotal.setString(2, e.getKey()); updateTotal.executeUpdate(); con.commit(); } } catch (SQLException e ) { JDBCTutorialUtilities.printSQLException(e); if (con != null) { try { System.err.print("Transaction is being rolled back"); con.rollback(); } catch(SQLException excep) { JDBCTutorialUtilities.printSQLException(excep); } } } finally { if (updateSales != null) { updateSales.close(); } if (updateTotal != null) { updateTotal.close(); } con.setAutoCommit(true); } }
ใน method นี้จะ auto-commit mode เป็น disable ซึ่งหมายถึง 2 prepared statements จะ commit รวมกัน เมื่อ commit มีการเรียก
ในคำสั่ง con.setAutoCommit(true); จะหมายถึงการกลับไปยัง สถานะ default เมื่อคำสั่งต่างๆเสร็จสิ้้น
Using Transactions to Preserve Data Integrity
ตัวอย่างของ transaction isolation level คือTRANSACTION_READ_COMMITTED จะไม่ยอมรับการเข้าถึงข้อมูลจนกว่า transaction เสร็จสิ้น พูดอย่างอย่างคือ DBMS จะไม่ยอมรับการมี dirty reads เกิดขึ้นTransaction Isolation Level แบ่งออกเป็น 5 ระดับ ดังนี้
Isolation Level Transactions Dirty Reads Non-Repeatable Reads Phantom Reads TRANSACTION_NONENot supported Not applicable Not applicable Not applicable TRANSACTION_READ_COMMITTEDSupported Prevented Allowed Allowed TRANSACTION_READ_UNCOMMITTEDSupported Allowed Allowed Allowed TRANSACTION_REPEATABLE_READSupported Prevented Prevented Allowed TRANSACTION_SERIALIZABLESupported Prevented Prevented Prevented non-repeatable read เกิดขึ้นเมื่อ transaction A รับค่าแถว,ลำดับต่อมา transaction B update แถว และลำดับต่อมา transaction A รับค่าที่แถวเดิมอีกครั้ง transaction A รับค่าที่แถวเดิม 2 ครั้งแต่ได้ค่าต่างไปจากเดิมphantom read เกิดขึ้นเมื่อ transaction A รับค่าจะแถวโดยผ่าน condition (where),ลำดับต่อมา transaction B ก็ทำการเพิ่มและ update แถวโดยผ่าน condition เดียวกันกับ transaction A ต่อมา transaction A ก็มารับค่าตาม condition อีกครั้ง แต่ปรากฏว่าเห็นแถวเพิ่มขึ้น แถวที่เพิ่มขึ้นนี้เองเรียกว่า phantomโดยทั่วไปเราไม่ต้องทำอะไรเกี่ยวกับTransaction Isolation Level สามารถใช้ค่า defalut ของ DBMS ได้เลย ค่า default ของ DBMS จะขึ้นอยู่กับ DBMS ที่ใช้ เช่น Java DB คือTRANSACTION_READ_COMMITTED ถ้าต้องการหาว่า DBMS ใช้ Level ไหนใช้คำสั่งConnectionmethodgetTransactionIsolation และถ้าต้องการ set เองใช้ConnectionmethodsetTransactionIsolationNote JDBC driver อาจจะไม่ support transaction level ทั้งหมด ถ้าไม่ support level ที่ระบุในsetTransactionIsolation ก็สามารถสลับไปใช้ level ที่สูงกว่า ถ้า driver ไม่สามารถสลับไปที่ level ที่สูงกว่าได้จะเกิด SQLException ใช้ methodDatabaseMetaData.supportsTransactionIsolationLevel ในการหาว่า driver support level ไหนSetting and Rolling Back to Savepoints
methodConnection.setSavepoint คือ set Savepoint Object ใน transaction ปัจจุบันConnection.rollbackmethod คือส่ง Savepoint ไปเป็น agumentตัวอย่างถ้าต้องการเพิ่มราคาแล้วราคานั้นเกินกว่าที่กำหนดไว้ก็จะ rollback ไปค่าเริ่มต้นใหม่อีกครั้งpublic void modifyPricesByPercentage( String coffeeName, float priceModifier, float maximumPrice) throws SQLException { con.setAutoCommit(false); Statement getPrice = null; Statement updatePrice = null; ResultSet rs = null; String query = "SELECT COF_NAME, PRICE FROM COFFEES " + "WHERE COF_NAME = '" + coffeeName + "'"; try { Savepoint save1 = con.setSavepoint(); getPrice = con.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); updatePrice = con.createStatement(); if (!getPrice.execute(query)) { System.out.println( "Could not find entry " + "for coffee named " + coffeeName); } else { rs = getPrice.getResultSet(); rs.first(); float oldPrice = rs.getFloat("PRICE"); float newPrice = oldPrice + (oldPrice * priceModifier); System.out.println( "Old price of " + coffeeName + " is " + oldPrice); System.out.println( "New price of " + coffeeName + " is " + newPrice); System.out.println( "Performing update..."); updatePrice.executeUpdate( "UPDATE COFFEES SET PRICE = " + newPrice + " WHERE COF_NAME = '" + coffeeName + "'"); System.out.println( "\nCOFFEES table after " + "update:"); CoffeesTable.viewTable(con); if (newPrice > maximumPrice) { System.out.println( "\nThe new price, " + newPrice + ", is greater than the " + "maximum price, " + maximumPrice + ". Rolling back the " + "transaction..."); con.rollback(save1); System.out.println( "\nCOFFEES table " + "after rollback:"); CoffeesTable.viewTable(con); } con.commit(); } } catch (SQLException e) { JDBCTutorialUtilities.printSQLException(e); } finally { if (getPrice != null) { getPrice.close(); } if (updatePrice != null) { updatePrice.close(); } con.setAutoCommit(true); } }method เริ่มต้นโดยสร้าง Savepoint ด้วยคำสั่ง Savepoint save1 = con.setSavepoint();method จะทำการตรวจสอบค่า new price ว่ามากกว่า maximum price หรือไม่ถ้ามากกว่าก็ให้กลับไปค่าปัจจุบัน con.rollback(save1);ดังนั้น เมื่อ method commit transaction โดยเรียกConnection.commitmethod มันจะไม่ commit แถวใดๆที่มีความสัมพันธ์กับ Savepoint ที่มีการ rolled back มันจะ commit แถวอื่นReleasing Savepoints
methodConnection.releaseSavepoint โดยป้อน Savepoint Object เป็น parameter และจะ remove Savepoint จาก transaction ปัจจุบันSavepoint จะ Release โดยอัตโนมัติ เมื่อมีการ commit หรือเมื่อ transaction rolle backการเรียน method rollback จะทำให้ออกจาก transaction และทำการ return ค่าใดที่ทำการเปลียนแปลงก่อนหน้าให้เป็นค่าเริ่มต้น ถ้าคุณทดลอง execute statment ใน transaction จะทำให้เกิด SQLException การเรียก method จะทำให้ transaction จบ และทำการเริ่มต้น transacton ใหม่อีกครั้ง
No comments:
Post a Comment