JDBC事務

有時我們使用JDBC操作數據庫時,會出現同時執行兩條Insert或update或delete之類的語句。


例如:有兩個人Martin和John,Martin有1000元,John有700元。假設某天Martin要轉100元給John,那麼數據庫應該會這樣執行:

Update Martin set monry = money -100 ;

Update John set money = money +100 ;

當兩個語句都執行了,纔可以算完成一個轉賬。否則其中一條語句沒執行,將會出現嚴重後果。而事物就是在這種背景下使用。


事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱爲ACID特性

原子性(atomicity)。一個事務是一個不可分割的工作單位,事務中包括的諸操作要麼都做,要麼都不做。

一致性(consistency)。事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。

隔離性(isolation)。一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。

持久性(durability)。持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

下面就模仿事物中的原子性:SQL語句要麼全部執行,要麼全部都不執行。


下面模擬:

1,以上面的例子建立數據庫:

create table bank(
   id int primary key auto_increment ,
   name varchar(20) not null ,
   money double not null default 0.00
) ;

insert into bank (name ,money) values("Martin" , 1000) ;
insert into bank (name ,money) values("John" , 700) ;

(圖1)

2,我們模擬在update語句執行的過程中遇到了異常,這個異常可能是斷電,數據庫出現異常或自然災害等。我們用1/0這個異常來代替

public class JDBC {
    public static void main(String[] args) {
    	Connection conn = null ;
    	Statement stat = null ;
	    try {
			Class.forName("com.mysql.jdbc.Driver") ;
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc" , "root","jian") ;
			
			String sql1 = "update bank set money=money-100 where name='Martin'" ;
			String sql2 = "update bank set money=money-100 where name='John'" ;
			
			stat = conn.createStatement() ;
			stat.executeUpdate(sql1) ;
			
			//模擬異常出現
			int x = 1/0 ;
			
			
			stat.executeUpdate(sql2) ;
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			if(null!=conn){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				conn = null ;
			}
			if(null!=stat){
				try {
					stat.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				stat = null ;
			}
		}
	}
    
    
}


沒有事物,相對於圖1發生了更新的異常

(圖2)

3,使用了事務

public class JDBC {
    public static void main(String[] args) {
    	Connection conn = null ;
    	Statement stat = null ;
	    try {
			Class.forName("com.mysql.jdbc.Driver") ;
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc" , "root","jian") ;
			
			String sql1 = "update bank set money=money-100 where name='Martin'" ;
			String sql2 = "update bank set money=money-100 where name='John'" ;
			//設置不主動提交事務
			conn.setAutoCommit(false);
			stat = conn.createStatement() ;
			
			stat.executeUpdate(sql1) ;
			//模擬異常出現
			int x = 1/0 ;
			stat.executeUpdate(sql2) ;
			
			//當兩個update都完成了,在提交事務
			conn.commit();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch(ArithmeticException e){
			//出現異常則回滾事務
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
	    finally{
			if(null!=conn){
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				conn = null ;
			}
			if(null!=stat){
				try {
					stat.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
				stat = null ;
			}
		}
	}
    
    
}

(圖3)


當使用了事務後,結果如圖3所示,相對於圖2沒有發生任何更新,在出現異常後回滾事務。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章