事務
事務及處理
事務由一組SQL語句組成。所謂事務處理,是指應用程式保證事務中的SQL語句要麼全部都執行,要麼一個都不執行。
事務處理是保證資料庫中資料完整性與一緻性的重要機制。應用程式和資料庫建立連接配接之後,可能使用多條SQL語句操作資料庫中的一個表或多個表,例如,一個管理資金轉賬的應用程式為了完成一個簡單的轉賬業務可能需要兩條SQL語句,即需要将資料庫user表中id号是0001的記錄的userMoney字段的值由原來的100更改為50,然後将id号是0002的記錄的userMoney字段的值由原來的20更新為70。應用程式必須保證這兩條SQL語句要麼全都執行,要麼全都不執行。
JDBC事務處理步驟
①用setAutoCommit(booean b)方法關閉自動送出模式
所謂關閉自動送出模式,就是關閉SQL語句的即刻生效性。和資料庫建立一個連接配接對象後,例如con,那麼con的送出模式是自動送出模式,即該連接配接對象con産生的Statement (PreparedStatement對象)對資料庫送出任何一條SQL語句操作都會立刻生效,使得資料庫中的資料可能發生變化,這顯然不能滿足事務處理的要求。例如,在轉賬操作時,将使用者0001的userMoney的值由原來的100更改為50的操作不應當立刻生效,而應等到0002使用者的userMoney的值由原來的20更新為70後一起生效,如果第二條SQL語句操作未能成功,第一條SQL語句操作就不應當生效。為了能進行事務處理,必須關閉con的這個預設設定。
con對象首先調用setAutoCommit (boolean autoCommit)方法,将參數autoCommit取值false來關閉預設設定:
con.setAutoCommit(false);
注意,先關閉自動送出模式,再擷取Statement對象sql:
sql = con.createStatement();
②用commit()方法處理事務
con調用setAutoCommit(false)後,con所産生的Statement對象對資料庫送出任何一條SQL語句都不會立刻生效,這樣一來,就有機會讓Statement對象(PreparedStatement對象)送出多條SQL語句,這些SQL語句就是一個事務。事務中的SQL語句不會立刻生效,直到連接配接對象con調用commit()方法。con調用commit()方法就是試圖讓事務中的SQL語句全部生效。
③用rollback()方法處理事務失敗
所謂處理事務失敗,就是撤銷事務所做的操作。con調用commit()方法進行事務處理時,隻要事務中任何一個SQL語句未能成功生效,就抛出SQLException異常。在處理SQLException異常時,必須讓con調用rollback()方法,其作用是:撤銷事務中成功執行的SQL語句對資料庫資料所做的更新、插入或删除操作,即撤銷引起資料發生變化的SQL語句所産生的操作,将資料庫中的資料恢複到commit()方法執行之前的狀态。
下面的例子7使用了事務處理,将mess表中number字段是R1001的height的值減少n,并将減少的n增加到字段是R1002的height上(使用了例子2中的GetDBConnection類)。程式代碼如下所示:
import java.sql.*;public class Example7 { public static void main(String[] args) { Connection con = null; Statement sql; ResultSet rs; String sqlStr; con = GetDBConnection.connectDB ("students", "root", ""); if(con == null) return; try{ float n = 0.02f; con.setAutoCommit(false); //先關閉自動送出模式 sql = con.createStatement(); //再傳回Statement對象 sqlStr = "select name,height from mess where number='R1001'"; rs = sql.executeQuery(sqlStr); rs.next(); float h1 = rs.getFloat(2); System.out.println("事務之前"+rs.getString(1)+"身高:"+h1); sqlStr = "select name,height from mess where number='R1002'"; rs = sql.executeQuery(sqlStr); rs.next(); float h2 = rs.getFloat(2); System.out.println("事務之前"+rs.getString(1)+"身高:"+h2); h1 = h1-n; h2 = h2+n; sqlStr = "update mess set height ="+h1+" where number='R1001'"; sql.executeUpdate(sqlStr); sqlStr = "update mess set height ="+h2+" where number='R1002'"; sql.executeUpdate(sqlStr); con.commit(); //開始事務處理,如果發生異常直接執行catch塊 con.setAutoCommit(true); //恢複自動送出模式 String s ="select name,height from mess where number='R1001'or number='R1002'"; rs = sql.executeQuery(s); while(rs.next()) { System.out.println("事務之後"+rs.getString(1)+"身高:"+rs.getFloat(2)); } con.close(); } catch (SQLException e) { try { con.rollback(); //撤銷事務所做的操作 } catch(SQLException exp) {} } }}
程式運作結果如圖所示: