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_NONE
Not supported Not applicable Not applicable Not applicable TRANSACTION_READ_COMMITTED
Supported Prevented Allowed Allowed TRANSACTION_READ_UNCOMMITTED
Supported Allowed Allowed Allowed TRANSACTION_REPEATABLE_READ
Supported Prevented Prevented Allowed TRANSACTION_SERIALIZABLE
Supported 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 ไหนใช้คำสั่ง
Connection
methodgetTransactionIsolation และถ้าต้องการ set เองใช้
Connection
methodsetTransactionIsolation
Note 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.rollback
method คือส่ง 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.commit
method มันจะไม่ 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