本地事務 事務類型 事務可以分為本地事務和分散式事務兩種類型。這兩種事務類型是根據訪問並更新的數據資源的多少來進行區分的。本地事務是在單個數據源上進行數據的訪問和更新,而分散式事務是跨越多個數據源來進行數據的訪問和更新。在這裡要說的事務是基於資料庫這種數據源的。 JDBC事務 在JAVA中,我們使用 ...
本地事務
事務類型
事務可以分為本地事務和分散式事務兩種類型。這兩種事務類型是根據訪問並更新的數據資源的多少來進行區分的。本地事務是在單個數據源上進行數據的訪問和更新,而分散式事務是跨越多個數據源來進行數據的訪問和更新。在這裡要說的事務是基於資料庫這種數據源的。
JDBC事務
在JAVA中,我們使用JDBC來連接資料庫,訪問和更新數據。那麼在JDBC中是如何實現事務的,事務是被誰來管理的?這個答案當然是資料庫,JDBC本身並沒有處理事務的能力,而是依賴於底層資料庫,底層資料庫來提供事務的服務。在很多資料上會提到,JDBC的事務是基於連接的,也就是那個Connection對象,這個連接的本質其實是連接到資料庫的一個Socket,與資料庫建立連接以後就可以向資料庫發送指令和數據,最終資料庫會根據接收到的指令和數據來進行增刪改查以及事務的處理。另外,事務是被限制在單個連接上的,這就好像我們去銀行的營業廳辦理業務,營業廳有多個視窗,我們只會在自己的視窗上與銀行工作人員進行溝通並處理自身的業務,而不能跨視窗,告訴別的視窗的工作人員把那哥們的錢轉到自己卡上,這事也就只能想想。
資料庫事務例子
下麵先看一個MYSQL資料庫事務的例子:
1、創建表
創建用戶表
CREATE TABLE USERS ( USER_ID INT NOT NULL AUTO_INCREMENT COMMENT '自增主鍵', USER_NAME VARCHAR(25) NOT NULL COMMENT '用戶名', PASSWORD VARCHAR(25) NOT NULL COMMENT '密碼', GENDER VARCHAR(1) COMMENT '性別', PHONE_NO VARCHAR(11) NOT NULL COMMENT '手機號', CREATE_TIME DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP() COMMENT '創建時間', PRIMARY KEY (USER_ID) ) COMMENT = '用戶表';
創建用戶和角色的關聯關係表
CREATE TABLE USER_ROLE_RELATION ( REL_ID INT NOT NULL AUTO_INCREMENT COMMENT '自增主鍵', USER_ID INT NOT NULL COMMENT '用戶ID', ROLE_ID INT NOT NULL COMMENT '角色ID', PRIMARY KEY (REL_ID) ) COMMENT = '用戶和角色對應關係表'
2、創建存儲過程,在存儲過程中使用事務
BEGIN #聲明一個標誌位,預設為0 DECLARE T_ERROR INTEGER DEFAULT 0; #如果事務執行過程中出現異常,那麼把標誌位設置為1 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET T_ERROR = 1; #開始事務 START TRANSACTION;
INSERT INTO USERS (USER_NAME, PASSWORD, GENDER, PHONE_NO) VALUES ('zhangsan', '123456', '男', '11111111111'); INSERT INTO USER_ROLE_RELATION (USER_ID, ROLE_ID) VALUES ('333', '1'); #如果執行成功,直接提交,否則回滾 IF T_ERROR = 0 THEN COMMIT; ELSE ROLLBACK; END IF; END
3、執行存儲過程
存儲過程執行成功以後,資料庫的這兩個表中會分別出現一條記錄。然後把
INSERT INTO USER_ROLE_RELATION (USER_ID, ROLE_ID) VALUES ('333', '1');
這個語句改為:
#這條INSERT語句違反了非空約束,會拋出異常 INSERT INTO USER_ROLE_RELATION (USER_ID, ROLE_ID) VALUES (NULL, '1');
重新保存並執行存儲過程,結果是兩個表中都沒有新增記錄。兩條SQL語句要麼同時成功,要麼同時失敗。
JDBC事務例子
JDBC中如果需要手動提交事務的話,需要用到Connection對象中的三個方法:
//設置是否自動提交 setAutoCommit() //提交 commit() //回滾 rollback()
在JDBC中事務的提交方式預設是自動提交的,手動提交的事務的話需要更改預設設置:
Connection.setAutoCommit(false)
下麵這個例子是假設新增一個用戶並給用戶賦預設許可權,那麼需要同時向兩張表中分別插入一條記錄,把新增用戶和賦許可權看做是一個執行單元,放在一個事務中。
package person.lb.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestJDBCTransAction { static { try { //載入驅動類 Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) { //執行事務 executeTransaction(); } private static void executeTransaction() { Connection conn = null; Statement st1 = null; Statement st2 = null; ResultSet rs = null; try { //獲取資料庫連接 conn = (Connection) DriverManager.getConnection( "jdbc:mysql://192.168.0.105:3306/TEST", "root", "root"); conn.setAutoCommit(false); st1 = (Statement) conn.createStatement(); st2 = (Statement) conn.createStatement(); //插入用戶信息 st1.execute("INSERT INTO USERS (USER_NAME, PASSWORD, GENDER, PHONE_NO) " + "VALUES ('zhangsan', '123456', '男', '11111111111')" , Statement.RETURN_GENERATED_KEYS); //獲取增長列的新值 rs = st1.getGeneratedKeys(); String userID = ""; if(rs.next()) { userID = rs.getString(1); } //插入用戶和角色關聯數據 st2.execute("INSERT INTO USER_ROLE_RELATION (USER_ID, ROLE_ID) VALUES (" +userID +", '1')"); conn.commit(); } catch (SQLException e) { e.printStackTrace(); try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } } finally { try { if(rs != null) { rs.close(); } if(st1 != null) { st1.close(); } if(st2 != null) { st2.close(); } if(conn != null) { conn.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
程式執行結果如下:
USERS表
USER_ROLE_RELATION表
到這裡,JAVA的本地事務算是寫完了。