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); } }