JDBC高級操作和事務處理(mysql)

JDBC批處理

  • piliang處理允許將相關的SQL語句分組到批處理中,並通過對數據庫的一次調用提交它們
  • 當需要一次向數據庫發送多個SQL語句時,可以減少連接數據庫的開銷,從而提高性能
  • 在jdbc的URL中添加rewriteBatchedStatements=true參數,可以提高批處理執行效率
Statement批處理
  • 以下是使用語句對象的批處理的典型步驟
註冊驅動獲取連接
使用createStatement()方法創建Statements對象
使用setAutoCommit()將auto_commit設置爲false
使用使用addBatch()方法在創建的語句對象上添加您喜歡的SQL語句到批處理中
在創建的語句對象上使用executeBatch()方法執行所有SQL語句
使用commit()方法提交所有更改
釋放資源
  • 經典步驟
package waking.test.jdbc;

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

/**
 * Statement批處理
 * @author waking
 *
 */
public class Demo10 {
	public static void main(String[] args) {
		// 驅動
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 聲明連接
		Connection conn = null;
		Statement stmt = null;
		
		try {
			// 加載驅動
			Class.forName(dirver);
			// 創建連接
			conn = DriverManager.getConnection(url, user, password);
			// 查詢
			stmt = conn.createStatement();
			// 開啓事務
			conn.setAutoCommit(false);
			// 返回結果
			// sql語句
			String sql1 = "insert into user values(8,'waki','wakig','xixix','17273934784')";
			stmt.addBatch(sql1);
			String sql2 = "insert into user values(9,'wa','wak','hee','17273934784')";
			stmt.addBatch(sql2);
			int[] executeBatch = stmt.executeBatch();
			// 提交事務
			conn.commit();
			System.out.println("影響"+executeBatch.length+"行");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			// 關閉連接
			if(stmt!=null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
  • 簡易步驟
// 以上開啓事務和關閉事務可以省略
String sql1 = "insert into user values(8,'waki','wakig','xixix','17273934784')";
			stmt.addBatch(sql1);
			String sql2 = "insert into user values(9,'wa','wak','hee','17273934784')";
			stmt.addBatch(sql2);
			int[] executeBatch = stmt.executeBatch();
PrepareStatement批處理
使用佔位符創建SQL語句
使用PrepareStatement()方法創建PrepareStatement對象
使用setAutoCommit()將auto_commit設置爲false
使用addBatch()方法在創建的語句對象上添加您喜歡的SQL語句到批處理
在創建的語句對象上使用executeBatch()方法執行所有SQL語句
最後,使用commit()方法提交所有更改
package waking.test.jdbc;

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

/**
 * PreparedStatement批處理
 * @author waking
 *
 */
public class Demo11 {
	public static void main(String[] args) {
		// 驅動
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 聲明連接
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try {
			// 加載驅動
			Class.forName(dirver);
			// 創建連接
			conn = DriverManager.getConnection(url, user, password);
			// 查詢
			// sql語句
			String sql1 = "insert into user values(?,?,?,?,?)";
			// 8,'waki','wakig','xixix','17273934784'
			pstmt = conn.prepareStatement(sql1);
			// 開啓事務
			conn.setAutoCommit(false);
			
			pstmt.setInt(1, 10);
			pstmt.setString(2, "wakk");
			pstmt.setString(3, "fdas");
			pstmt.setString(4, "asa");
			pstmt.setString(5, "17273934784");
			pstmt.addBatch();	
			
			pstmt.setInt(1, 11);
			pstmt.setString(2, "akk");
			pstmt.setString(3, "fs");
			pstmt.setString(4, "aa");
			pstmt.setString(5, "17273934784");
			pstmt.addBatch();
			// 返回結果
			int[] executeBatch = pstmt.executeBatch();
			// 提交事務
			conn.commit();
			System.out.println("影響"+executeBatch.length+"行");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			// 關閉連接
			if(pstmt!=null) {
				try {
					pstmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
Statment批處理和PrepareStatement批處理區別
  • Statement批處理可以添加不同SQL語句,而PrepareStatement只能添加一種SQL語句
  • PrepareStatement效率比Statement高,而且更安全

數據庫事務

事務概述
  • 一組要麼同時執行成功,要麼同時失敗的SQL語句。是數據庫操作的一個不能分割執行單元
數據庫事務(Database Transaction),是指作爲單個邏輯單元執行的一系列操作,要麼完全的執行,要麼完全的不執行。
事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。
通過將一組相關操作組合爲一個要麼全部成功要麼全部失敗的單元,可以簡化錯誤恢復並使應用程序更可靠。
一個邏輯工作單元要成爲事務,必須滿足所謂的ACID(原子性,一致性,隔離性,持久性)屬性。
事務是數據庫運行中的邏輯工作單位,有DBMS中的事務管理子系統負責事務的處理。
通常事務開始於
  • 連接到數據庫上,並執行一條DML語句insert,update或delete
  • 前一個事務結束後,又輸入了另一條DML語句
通常事務結束於
  • 執行commit後rollback語句
  • 執行一條DDL語句,列如create table語句,在這種情況下,會自動執行commit語句
  • 斷開與數據庫的連接
  • 執行了一條DML語句,該語句卻失敗了,在這種情況中,會爲這個無效的DML語句執行rollback語句
事務特性(ACID)
  • Atomicity(原子性)
    • 表示一個事務內的所有操作是一個整體,要麼全部成功,要麼全部失敗
  • Consistency(一致性)
    • 表示一個事務內有一個操作失敗時,所有的更改過的數據都必須回滾到修改前狀態
  • Isolation(隔離性)
    • 事務查看數據時數據所處的狀態,要麼是另一併發事務修改它之前的狀態,要麼是另一事務修改它之後的狀態,事務不會查看中間狀態的數據
  • Durability(持久性)
    • 持久性事務完成之後,它對於系統的影響是永久的
  • 數據庫操作
CREATE TABLE account(
	id INT PRIMARY KEY,
	NAME VARCHAR(20)NOT NULL,
	money DOUBLE(10,2)
);
INSERT INTO account(id,NAME,money) VALUES(1,'wkaing',100),(2,'lily',100);
  • java代碼
package waking.test.jdbc;

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

/**
 * 事務處理
 * @author waking
 *
 */
public class Demo12 {
	public static void main(String[] args) {
		// 驅動
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 聲明連接
		Connection conn = null;
		PreparedStatement pstmt1 = null;
		PreparedStatement pstmt2 = null;
		try {
			// 加載驅動
			Class.forName(dirver);
			// 創建連接
			conn = DriverManager.getConnection(url, user, password);
			// 開啓事務
			conn.setAutoCommit(false);
			// 查詢
			// sql語句
			String sql1 = "update account set money = money - 100 where id = ?";
			String sql2 = "update account set money = money + 100 where id = ?";
			pstmt1 = conn.prepareStatement(sql1);
			
			pstmt1.setInt(1, 1);
			// 返回結果
			pstmt1.executeUpdate();
			
			pstmt2 = conn.prepareStatement(sql2);
			pstmt2.setInt(1, 2);
			pstmt2.executeUpdate();
			System.out.println("轉賬成功、、");
			// 提交事務
			conn.commit();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("轉賬失敗、、、");
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
			// 關閉連接
			if(pstmt1!=null) {
				try {
					pstmt1.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(pstmt2!=null) {
				try {
					pstmt2.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
Mysql事務語句
#開啓事務
START TRANSACTION;
UPDATE account SET money = money-100 WHERE id =1;
UPDATE account SET money = money+100 WHERE id =2;
#提交事務
COMMIT;
#回滾事務
ROLLBACK;

事務的隔離級別

  • 一個事務,在併發訪問的情況下,不同隔離級別會出現不同效果
  • 併發:在同一時刻,有多個客戶在操作同一張表
1.read uncommitted
一個事務中讀到了另一個事務並未提交的結果。
這種隔離級別就會導致:髒讀、不可重複讀、幻讀
2.read committed (oracle的默認隔離級別)
一個事務中能讀到另一個事務已經提交的結果,但是不能讀到另一個事務沒有提交的結果
這種隔離級別解決了髒讀問題。但出現了不可從重複讀和幻讀的問題
注:
所謂的不可重複讀,就是不能重複讀,一重複讀數據就不一樣
所謂的幻讀,在一個事務中,兩次讀到的數據的條數不相同
3.repeatable read(mysql的默認級別)
一個事務中可以重複讀,每次讀到的數據都是一樣的
無論其他事務對數據進行怎樣的操作(添加數據、修改數據、提交事務)。當前事務每次讀到的數據內容都不會有變化
這種隔離級別解決了:髒讀、不可重複讀,幻讀
4.serializable串行化
最嚴苛的隔離級別。將並行變成串行。效率非常低。
  • mysql查看事務隔離級別
    • select @@tx_isolation
  • 設置隔離級別
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
Savepoint
  • Connection對象有兩種新的方法來幫助您管理保存點 -
  • setSavepoint(String savepointName):定義新的保存點。它還返回一個Savepoint對象。
  • releaseSavepoint(Savepoint savepointName):刪除保存點。請注意,它需要一個Savepoint對象作爲參數。此對象通常是由setSavepoint()方法生成的保存點。
package waking.test.jdbc;

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

/**
 *  事務處理
 *  savepoint
 * @author waking
 *
 */
public class Demo13 {
	public static void main(String[] args) {
		// 驅動
		String dirver = "com.mysql.jdbc.Driver";
		// url
		String url = "jdbc:mysql://localhost:3306/csdn";
		// user
		String user = "root";
		// password
		String password = "123456";
		
		// 聲明連接
		Connection conn = null;
		Statement stmt = null;
		Savepoint savepoint=null;
		try {
			// 加載驅動
			Class.forName(dirver);
			// 創建連接
			conn = DriverManager.getConnection(url, user, password);
			// 開啓事務
			conn.setAutoCommit(false);
			// 查詢
			// sql語句
			String sql = "update account set money = money - 100 where id = 1";
			
			stmt = conn.createStatement();
			stmt.executeUpdate(sql);
			savepoint= conn.setSavepoint("save");

			String sql1 = "update account set money = money + 100 where id = 2";
			
			stmt.executeUpdate(sql1);
			conn.commit();
			System.out.println("轉賬成功、、");
			// 提交事務
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("轉賬失敗、、、");
			try {
				//回滾事務
				conn.rollback(savepoint);
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
			// 關閉連接
			if(stmt!=null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(conn!=null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

}
感謝您的觀看
發佈了19 篇原創文章 · 獲贊 19 · 訪問量 5633
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章