一、MySql事務
之前在Oracle中已經學習過事務了,這個東西就是這個東西,但是在MySql中用法還是有一點不同,正好再次回顧一下。
先看看MySql中的事務,默認情況下,每執行一條SQL語句,都是一個單獨的事務。如果需要在一個事務中包含多條SQL語句,就需要開啟和結束事務。
開始事務:start transaction
結束事務:commit或rollback
在執行SQL語句之前,先執行start transaction,這就開啟了一個新的事務,然后就可以去執行多條SQL語句,最后要結束事務,commit表示提交,即事務中多條SQL語句造成的影響會持久化到數據庫中。rollback表示回滾,一切恢復到事務的起點,事務開始之后所到的操作全當沒有發生過。
在orcale中拿銀行轉賬舉過例子,現在在MySql中實現以下:
首先建了一個銀行賬戶表
現在張三余額800,李四余額1200,下面李四向張三轉賬200.
在兩句update語句之后數據庫貌似是變了,這時候注意其他用戶看到的還是沒有變化的數據庫,因為沒有提交,這時候在本用戶查看好像是轉成功了,但是一個rollback,一切歸於開始。
二、JDBC事務
JDBC操作事務,全部都是由Connection完成。Connection的三個方法與事務有關
setAutoCommit(boolean):設置是否自動提交事務,如果不自動提交,那這句就表示事務的開始。
commit():表示提交事務
rollback():表示回滾事務
JDBC操作事務的代碼格式
try{
con.setAutoCommit(fasle);
....
....
con.commit();
}catch(){
con.rollback();
}
如果對事務的操作拋出異常,那么肯定就執行不來,所以回滾,要是沒有出錯,那就提交。
這里一定要注意的JDBC操作事務一定要使用一個Connection對象!!!!再拿銀行轉賬來演示,首先建一個賬戶類。
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * @author WangXinwei *使用自建工具類JdbcUntils返回Connection對象 */
public class Bank { public void account(String name,int blance) throws SQLException{ Connection conn=JdbcUntils.getConn(); String sql="update bank set blance=blance+? where name=?"; PreparedStatement ps=conn.prepareStatement(sql); ps.setInt(1, blance); ps.setString(2, name); ps.executeUpdate(); } }
使用JDBC操作事務
import java.sql.Connection; import java.sql.SQLException; /** * @author WangXinwei * 傳入轉賬方,收賬方,轉賬金額 * */
public class Demo3 { public void demo(String from, String to, int money) { Connection conn = JdbcUntils.getConn(); try { conn.setAutoCommit(false); Bank bank = new Bank(); bank.account(from, -money); bank.account(to, +money); conn.commit(); } catch (Exception e) { // TODO: handle exception
try { conn.rollback(); conn.close(); } catch (SQLException e1) { // TODO Auto-generated catch block
e1.printStackTrace(); } } finally { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block
e.printStackTrace(); } } } }
因為我使用的是單例模式返回的Connection對象,所以是一個對象,滿足之前說的。
三、事務的隔離級別
事務的問題一般都是出現的並發操作的時候。
並發事務問題有五種,其中兩種是更新問題,三種是讀問題。重點看並發讀問題,在這之前,先略微了解一下更新問題
1. 第一類丟失更新(lost update): 在完全未隔離事務的情況下,兩個事務更新同一條數據資源,某一事務異常終止,回滾造成第一個完成的更新也同時丟失。
2. 第二類丟失更新(second lost updates):是不可重復讀的特殊情況,如果兩個事務都讀取同一行,然后兩個都進行寫操作,並提交,第一個事務所做的改變就會丟失。
並發讀問題:
1.臟讀:讀到未提交更新數據,就是讀到另一個事務未提交數據,就是臟數據。
比如:
2.不可重復讀:對同一記錄兩次讀取不一致,因為另一事務對該記錄做了修改
比如:
3.幻讀:對同一張表的兩次查詢不一致,因為另一事務插入了一條數據
比如:
不可重復讀和幻讀有什么區別呢?
不可重復讀是讀到了另一個事務的更新
幻讀是讀到了另個一表的插入(MySql中無法測試幻讀)
四大隔離級別:
四個等級的隔離級別,在除了隔離級別不同什么都相同的情況下處理結果是不同的,因為四種隔離級別對並發數據的處理能力是不同的。
1.SERIALIZABLE(串行化)
因為是串行化,所以不會出現任何問題,效率最差
2.REPEATABLE READ(可重復讀)MySql默認
防止臟讀和不可重復讀,不能防止幻讀
3.READ COMMITTED(讀已提交數據)
防止臟讀
4.READ UNCOMMITTED(讀未提交數據)
可能出現任何問題,效率最好
查看MySql中隔離級別,使用select @@tx_isolation查看
也可以通過 set isolationlevel [4選1] 來設置隔離級別
JDBC設置隔離級別:
依舊通過Connection對象,使用方法setTransactionisolation[ int level]
參數可選為