SQL事務實例解釋事務,回滾,保存點的作用y與用法



事務:

在編寫業務的過程中,會需要進行事務處理,當需要執行多條插入語句時,如果前幾條成功,而最後一條失敗,那麼我們需要回滾數據庫操作,保持數據的一致性和完整性,此時,就需要利用DB的事務處理。事務是恢復和併發控制的基本單位。

        簡單來說,所謂的事務,是一個操作序列,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。

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







1.示例

當person1給person2轉賬10塊:
數據庫實現思路如下:先給person1減去10,再給2加上10。
那麼問題來了:
當person1減去10執行成功以後,在給person2加錢的時候出錯了。
最終造成結果是:
person1少了10快,person2的錢卻沒有變。因此,總錢少了10快。

2.沒有事務,正常執行
package tran;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
//實現的業務是:1給2轉10塊錢
public class Account {
	private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
	private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
	private static String jdbcuser = "root"; // 數據庫用戶名
	private static String jdbcpwd = "root"; // 數據庫密碼
	private static Connection conn;
	public static PreparedStatement ps;

	public static void main(String[] args) {
		try {
			Class.forName(jdbcDriver);
			conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
			ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
			ps.executeUpdate();
			ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 關閉資源
		}

	}
}

3.沒有事務,過程中出錯示例
//最終的執行結果是:從id person1的用戶裏減去了10塊錢,但是並沒有給person2加上。
//造成的結果是:總金額少了10塊。
package tran;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class Account {
	private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
	private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
	private static String jdbcuser = "root"; // 數據庫用戶名
	private static String jdbcpwd = "root"; // 數據庫密碼
	private static Connection conn;
	public static PreparedStatement ps;

	public static void main(String[] args) {
		try {
			Class.forName(jdbcDriver);
			conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
			ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
			ps.executeUpdate();
			int i=1/0;//這裏設置一個錯誤。
			ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 關閉資源
		}
	}
}

4.解決方案-事務
package tran;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Account {
	private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
	private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
	private static String jdbcuser = "root"; // 數據庫用戶名
	private static String jdbcpwd = "root"; // 數據庫密碼
	private static Connection conn;
	public static PreparedStatement ps;

	public static void main(String[] args) {
		try {
			Class.forName(jdbcDriver);
			conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
			conn.setAutoCommit(false);// 設置不自動提交
			ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
			ps.executeUpdate();
			int i = 1 / 0;
			ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
			ps.executeUpdate();
			conn.commit();// 如果上面的執行都沒問題,再提交。
		} catch (Exception e) {
			try {
				conn.rollback(); //如果出錯則 執行回滾
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			// 關閉資源
		}
	}
}
回滾的作用就是,當有一個SQL語句執行時,條件不符合要求,比如你要插入一個數據,但是插入的數據要有條件的,這時候你就可以用回滾,如果條件成功就COMMIT提交的意思,不然就ROLLBACK回滾,也就是說插入不成功


5.擴展-保存點
使用場景:
person1給person2轉錢,轉完給他們發短信。
以下是模擬。
package tran;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

public class Account {
	private static String jdbcDriver = "com.mysql.jdbc.Driver";// mysql連接驅動,無需改
	private static String jdbcUrl = "jdbc:mysql://localhost:3306/zdy";
	private static String jdbcuser = "root"; // 數據庫用戶名
	private static String jdbcpwd = "root"; // 數據庫密碼
	private static Connection conn;
	public static PreparedStatement ps;
	static Savepoint sp;

	public static void main(String[] args) {
		try {
			Class.forName(jdbcDriver);
			conn = DriverManager.getConnection(jdbcUrl, jdbcuser, jdbcpwd); // 驅動利用驅動地址,數據庫用戶名,密碼創建連接
			conn.setAutoCommit(false);// 設置不自動提交
			ps = conn.prepareStatement("UPDATE account set money=money-10 where uid=person1;");
			ps.executeUpdate();
			ps = conn.prepareStatement("UPDATE account set money=money+10 where uid=person2;");
			ps.executeUpdate();
			sp = conn.setSavepoint();//設置一個保存點
			// 發送短信業務
			// 模擬業務出錯
			int i = 1 / 0;//因爲不是重要業務部分,所以出錯後回滾到保存點提交數據到數據庫
			conn.commit();// 如果上面的執行都沒問題,再提交。
		} catch (Exception e) {
			if(sp!=null){//只簡單說明,實際還要判斷conn是不是null 
				try {
					conn.rollback(sp);//回滾到內個設置點
					conn.commit();//提交保存點之前的數據到數據庫
				} catch (SQLException e1) {
					e1.printStackTrace();
				}elseif(sp==null){ conn.rollback();//若果保存點之前出錯出錯    則回滾全部
}	
			}
			e.printStackTrace();
		} finally {
			// 關閉資源
		}
	}
}



       

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