Java中開啓事務操做數據庫

1、事務的四大特性(ACID)html

一、原子性(atomicity):組成事務的語句造成了一個邏輯單元,不能只執行一部分;數據庫

二、一致性(consistency):在事務處理執行先後,數據庫與理論值是一致的(數據庫完整性約束);數組

三、隔離性(isolcation):一個事務處理和另外一個事務處理相互間互不影響;多線程

四、持續性(durability):事務處理的效果可以被永久保存下來。併發

2、隔離級別性能

一、多線程併發執行可能會產生如下三個問題:測試

  髒讀(dirty reads):一個事務讀取了另外一個事務未提交的並行事務寫的數據;atom

  不可重複讀(non-repeatablereads):一個事務從新讀取前面讀取過的數據,發現該數據已經被另外一個已提交的事務修改過;線程

  幻讀(phantom read):一個事務從新執行一個查詢,返回一套符合條件的行,發現這些行由於最近提交的事務而發生了改變htm

二、隔離級別

  讀未提交(Read uncommitted):未解決

  讀已提交 (Read committed):已解決:髒讀

  可重複讀 (Repeatable read):已解決:髒讀,不可重複讀

  序列化 (Serializble):已解決:髒讀,不可重複讀,幻讀

三、設置隔離級別

  connection.setTransactionlsolation(Connection.事務級別)

  MySql默認爲度已提交;

3、Java操做

參考:https://www.cnblogs.com/zzzzw/p/4869334.html

1.開啓事務(非自動提交):用於批量提交或者事務完整性操做。

    默認狀況下,數據庫鏈接處於自動提交模式(autocommit mode)。每一個SQL語句一旦被執行便被提交給數據庫。一旦命令被提交,就沒法對它進行回滾操做。

    在使用事務時,須要關閉這個默認值:

conn.setAutoCommit(false);

 如今可使用一般的方法建立一個語句對象:

Statement stat = conn.createStatement();

    而後任意屢次調用executeUpdate方法:

stat.executeUpdate(command1);
stat.executeUpdate(command2);
...

    若是執行了全部命令以後沒有出錯,則調用commit方法:

conn.commit();

    若是出現錯誤,則調用:

conn.rollback();

    此時,程序將自動撤銷自上次提交以來的全部語句。當事務被SQLException異常中斷時,典型的方法就是發起回滾操做。

 

2.保存點:撤銷事務中的部分操做

 在使用某些驅動程序時,使用保存點(save point)能夠更細粒度地控制回滾操做。建立一個保存點意味着稍候只需返回到這個點,而非事務的開頭。例如,

Statement stat = conn.createStatement(); //開啓一個事務;rollback()返回這裏
stat.executeUpdate(command1);
Savepoint svpt = conn.setSavepoint(); //設置保存點;rollback(svpt)返回到這裏
stat.executeUpdate(command2);
if(...) conn.rollback(svpt);   //撤銷command2產生的影響
...
conn.commit(); //最後不要忘了提交事務,不然前面須要提交保存的操做也將不會保存到數據庫中

 當再也不須要保存點時,必須釋放它:

conn.releaseSavepoint(svpt);

 

3.批量更新

    假設有一個程序須要執行許多INSERT語句,以便將數據填入數據庫表中,此時可使用批量更新的方法來提升程序性能。在使用批量更新(batch update)時,一個語句序列做爲一批操做將同時被收集和提交。

注意:使用DatabaseMetaData接口中的supportsBatchUpdates方法能夠獲知數據庫是否支持這種特性。

  處於同一批中的語句能夠是INSERT、UPDATE和DELETE等操做,也能夠是數據庫定義語句,如CREATE TABLE和DROP TABLE。可是,在批量處理中添加SELECT語句會拋出異常(從概念上講,批量處理中的SELECT語句沒有意義,由於它會返回結果集,而不更新數據庫)。

  爲了執行批量處理,首先必須使用一般的辦法建立一個Statement對象:

Statement stat = conn.createStatement();

  如今應該調用addBatch方法,而非executeUpdate方法:

String command = "CREATE TABLE..."
stat.addBatch(command);

while(...){
    command = "INSERT INTO ... VALUES("+...+")";
    stat.addBatch(command);
}

  最後,提交整個批量更新語句:

int[] counts = stat.executeBatch();

  調用executeBatch方法將爲全部已提交的語句返回一個記錄數的數組。

  爲了在批量模式下正確地處理錯誤,必須將批量執行的操做視爲單個事務。若是批量更新在執行過程當中失敗,那麼必須將它回滾到批量操做開始以前的狀態。

  首先,關閉自動提交模式,而後收集批量操做,執行並提交該操做,最後恢復最初的自動提交模式:

boolean autoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
Statement stat = conn.getStatement();
...
//keep calling stat.addBatch(...);
...
stat.executeBatch();
conn.commit();
conn.setAutoCommit(true);

 

4.小例子(開啓,提交,回滾事務)

//更新學生信息
     public void update(Student s) {
         Connection connection = JDBCUtil_C3P0.getConnection();
         try {
             //關閉事務自動提交(開啓事務)
             connection.setAutoCommit(false);
             //在數據庫中查找學生本來所在班級
             int oldclazzid = studentDao.findById(s.getId()).getClazz().getId();
             //若是學生班級發生改變,對班級表進行修改
             if(oldclazzid !=s.getClazz().getId()){
                 //爲轉到的新班級增長一個學生
                 clazzDao.addClazzCount(connection, s.getClazz().getId());
                 //爲本來所在的舊班級減小一個學生
                 clazzDao.subClazzCount(connection, oldclazzid);
                 //測試事務,手動拋出一個SQL異常
                 //throw new SQLException("操做異常");
             }
             //修改學生信息
             studentDao.updateStudent(connection, s);
             //以上全部操做無異常則提交事務
             connection.commit();
             
         } catch (SQLException e) {
             e.printStackTrace();
             //一旦事務中有哪一步操做發生異常則進行事務回滾
             try {
                 connection.rollback();
             } catch (SQLException e1) {
                 e1.printStackTrace();
             }
         }finally{
             //關閉鏈接資源
             clazzDao.close(connection);
             studentDao.close(connection);
         }         
     }
相關文章
相關標籤/搜索