一、事務的四大特性(ACID)
1、原子性(atomicity):組成事務的語句形成了一個邏輯單元,不能只執行一部分;
2、一致性(consistency):在事務處理執行前后,數據庫與理論值是一致的(數據庫完整性約束);
3、隔離性(isolcation):一個事務處理和另一個事務處理相互間互不影響;
4、持續性(durability):事務處理的效果能夠被永久保存下來。
二、隔離級別
1、多線程並發執行可能會產生以下三個問題:
臟讀(dirtyreads):一個事務讀取了另一個事務未提交的並行事務寫的數據;
不可重復讀(non-repeatablereads):一個事務重新讀取前面讀取過的數據,發現該數據已經被另一個已提交的事務修改過;
幻讀(phantomread):一個事務重新執行一個查詢,返回一套符合條件的行,發現這些行因為最近提交的事務而發生了改變
2、隔離級別
讀未提交(Read uncommitted):未解決
讀已提交 (Readcommitted):已解決:臟讀
可重復讀 (Repeatableread):已解決:臟讀,不可重復讀
序列化 (Serializble):已解決:臟讀,不可重復讀,幻讀
3、設置隔離級別
connection.setTransactionlsolation(Connection.事務級別)
MySql默認為度已提交;
三、基本操作
1、connection.setAutCommit(false):關閉事務自動提交
2、connection.commit():手動提交事務
3、connection.rollback():事務回滾
補:撤銷事務中的部分操作
SavePoint sp = connection.setSavepoint();:設置事務回滾點
connection.rollback(sp);
connection.commit();:最后不要忘了提交事務,否則前面需要提交保存的操作也將不會保存到數據庫中
代碼示例:(修改學生並更新班級)
StudentDao.java:
1 public void updateStudent(Connection conn,Student s) throws SQLException{ 2 String sql = "update student set name = ?,age = ?,sex = ?,clazzid = ? where id = ?"; 3 try { 4 st = conn.prepareStatement(sql); 5 st.setString(1, s.getName()); 6 st.setInt(2, s.getAge()); 7 st.setString(3, s.getSex()); 8 st.setInt(4, s.getClazz().getId()); 9 st.setInt(5, s.getId()); 10 } catch (SQLException e) { 11 e.printStackTrace(); 12 } 13 /*上面只捕獲st = conn.prepareStatement(sql);的異常 14 * st.executeUpdate();最后將執行對數據庫更改的操作產生的異常拋出到上一層(Service)調用者 15 * connection開啟事務在Service中開啟 16 * 所以Connection來自Service中開啟事務的連接 17 */ 18 st.executeUpdate(); 19 }
ClazzDao.java:
1 //為學生所轉到的新班級增加一個人數 2 public void addClazzCount(Connection conn,int clazzid) throws SQLException{ 3 String sql = "update clazz set count = count + 1 where id =?"; 4 try { 5 st = conn.prepareStatement(sql); 6 st.setInt(1, clazzid); 7 } catch (SQLException e) { 8 e.printStackTrace(); 9 } 10 /*上面只捕獲st = conn.prepareStatement(sql);的異常 11 * st.executeUpdate();最后將執行對數據庫更改的操作產生的異常拋出到上一層(Service)調用者 12 * connection開啟事務在Service中開啟 13 * 所以Connection來自Service中開啟事務的連接 14 */ 15 st.executeUpdate(); 16 } 17 //為學生原來所在的班級減少一個人數 18 public void subClazzCount(Connection conn,int clazzid) throws SQLException{ 19 String sql = "update clazz set count = count -1 where id =?"; 20 try { 21 st = conn.prepareStatement(sql); 22 st.setInt(1, clazzid); 23 } catch (SQLException e) { 24 e.printStackTrace(); 25 } 26 /*上面只捕獲st = conn.prepareStatement(sql);的異常 27 * st.executeUpdate();最后將執行對數據庫更改的操作產生的異常拋出到上一層(Service)調用者 28 * connection開啟事務在Service中開啟 29 * 所以Connection來自Service中開啟事務的連接 30 */ 31 st.executeUpdate(); 32 }
重點來了!
Service中開啟,提交,回滾事務
Service.java
1 //更新學生信息 2 public void update(Student s) { 3 Connection connection = JDBCUtil_C3P0.getConnection(); 4 try { 5 //關閉事務自動提交(開啟事務) 6 connection.setAutoCommit(false); 7 //在數據庫中查找學生原本所在班級 8 int oldclazzid = studentDao.findById(s.getId()).getClazz().getId(); 9 //如果學生班級發生改變,對班級表進行修改 10 if(oldclazzid !=s.getClazz().getId()){ 11 //為轉到的新班級增加一個學生 12 clazzDao.addClazzCount(connection, s.getClazz().getId()); 13 //為原本所在的舊班級減少一個學生 14 clazzDao.subClazzCount(connection, oldclazzid); 15 //測試事務,手動拋出一個SQL異常 16 //throw new SQLException("操作異常"); 17 } 18 //修改學生信息 19 studentDao.updateStudent(connection, s); 20 //以上所有操作無異常則提交事務 21 connection.commit(); 22 23 } catch (SQLException e) { 24 e.printStackTrace(); 25 //一旦事務中有哪一步操作發生異常則進行事務回滾 26 try { 27 connection.rollback(); 28 } catch (SQLException e1) { 29 e1.printStackTrace(); 30 } 31 }finally{ 32 //關閉連接資源 33 clazzDao.close(connection); 34 studentDao.close(connection); 35 } 36 37 }
Over
