初學JDBC(八)-JDBC的事務處理
上一篇部落格講了CallableStatement介面呼叫儲存過程,這一篇部落格我來說說JDBC的事務處理,這在以後的專案開發中也很重要,只有充分地考慮好JDBC的事務處理,才能在專案開發中遇到前臺與後臺異常時,JDBC的事務處理可以很好地去彌補這一措施,在銀行,支付寶,金融,微信紅包等等中尤其顯得重要,不然的話如果我們給別人轉錢時發生異常,錢從我們的卡里扣出來了,但是對方卻沒有收到,豈不是尷尬了,怎麼樣?這個例子,一提到錢,眼睛就雪亮雪亮的,是不是對JDBC事務處理產生了好奇心,現在我就來說說JDBC的事務處理。
事務處理:英文名字:Transaction Processing;用於正確有效的記錄自己感性的資料處理記錄。事務(由幾個任務組成)是一個最小的工作單元,無論成功與否都要作為一個整體進行即要麼全部執行要麼全部都不執行,不存在執行了一部分另一部分沒有執行的情況發生。從而得出事務本身具有ACID的屬性。ACID就是原子性(Atomicity
原子性( Atomicity):是事務的最小單元,是不可在分割的單元,相當於一個個小的資料庫操作,這些操作必須同時成功才為成功,只要有一個失敗,則一切的操作都將失敗,這就是原子性。
一致性(Consistency):事務在系統完整性中實施一致性,通過保證系統的任何事務最後都處於有效狀態來實現。如果事務操作成功,那麼系統的所有變化將正確的應用於系統中,系統處於有效狀態。如果事務操作中出現錯誤,那麼系統中的所有事務將自動的發生回滾,返回到操作前的狀態來保持系統的一致性。
隔離性(Isolation):在隔離的狀態執行事務,使它們覺得好像是系統在某一個給定的時間段內執行唯一的操作,如果有兩個事務,執行在相同的時間段內,執行著相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用這個系統。
永續性(Durability):事務完成之後,它對於系統的影響將是永久的。即使該修改會產生致命的錯誤也會一直保持下去,直到有人修改了為止。
這裡我們來說一說mysql資料庫中的事物處理:它是由一個或者多個SQL語句序列結合在一起形成所形成的邏輯處理單元。事物處理中的每一條語句都是完成資料庫整個操作任務的一部分,所有的SQL語句結合在一起執行完畢,才能達到完成指定的目的。DBMS在對事務處理中的語句進行處理時,是按照一個約定成俗的規定進行處理的:事務處理中的所有語句都將被作為一個原子性的工作單位,所有語句要麼成功的一起執行,要麼一個也不執行。有了這種規定,在以後事務處理中發生異常就按照這種規定進行下去,保證了資料庫中的資料不會有髒資料的發生。不會產生巨大的危害,減輕了DBMS人員操作負擔。
mysql對事務處理的支援的命令:
1:begin:啟動事務相當於執行Start Transaction.
2:Start Transaction:啟動事務.
3:set autocommit=0/1:為0代表取消自動提交處理,開啟事務處理;為1代表開啟自動提交處理,關閉事務處理,系統預設情況為1.
4:commit:提交事務.
5:rollback:回滾全部事務.
6:savepoint 事務儲存點的名稱:設定事務儲存點.
7:rollback to savepoint 儲存點名稱:回滾操作到設定的儲存點。
講了這個多理論性的知識,再上一個程式碼示例來鞏固一下知識,(無程式碼,不程式嘛) 既然老提及錢,那我們這個例子就舉個和錢有關的例子吧。A借B10塊錢,A還B10塊錢。
建立表:
CREATE TABLE t_money(
id INT PRIMARY KEY AUTO_INCREMENT,
userName VARCHAR(20),
money INT
);
JDBC轉賬(借錢還錢)程式碼:
package com.panli.dbutil;
/**
* 連線資料庫
*/
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DbUtil {
//資料庫驅動名字
private static String jdbcName = "com.mysql.jdbc.Driver";
//資料庫協議地址
private static String dbUrl = "jdbc:mysql://localhost:3306/db_user";
//資料庫使用者名稱
private static String dbUser = "root";
//資料庫密碼
private static String dbPassword = "123456";
/**
* 獲取連線
* @return
* @throws Exception
*/
public static Connection getCon() throws Exception{
Class.forName(jdbcName);
Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
return conn;
}
/**
* 關閉連線
* @param stmt
* @param conn
* @throws Exception
*/
public static void close(Statement stmt,Connection conn) throws Exception{
if(stmt!=null){
stmt.close();
if(conn!=null){
conn.close();
}
}
}
/**
* 關閉連線
* @param cstmt
* @param conn
* @throws Exception
*/
public static void close(CallableStatement cstmt, Connection conn) throws Exception{
if(cstmt!=null){
cstmt.close();
if(conn!=null){
conn.close();
}
}
}
/**
* 關閉連線
* @param pstmt
* @param conn
* @throws SQLException
*/
public static void close(PreparedStatement pstmt, Connection conn) throws SQLException{
if(pstmt!=null){
pstmt.close();
if(conn!=null){
conn.close();
}
}
}
/**
* 過載關閉方法
* @param pstmt
* @param conn
* @throws Exception
*/
public void close(ResultSet rs,PreparedStatement pstmt, Connection conn) throws Exception{
if(rs!=null){
rs.close();
if(pstmt!=null){
pstmt.close();
if(conn!=null){
conn.close();
}
}
}
}
}
package com.panli.model;
public class Money {
private int id;
private String userName;
private int money;
/**
* 預設的構造方法
*/
public Money() {
super();
// TODO Auto-generated constructor stub
}
/**
* 2個引數的構造方法
* @param id
* @param money
*/
public Money(int id, int money) {
super();
this.id = id;
this.money = money;
}
/**
* 3個引數的構造方法
* @param id
* @param userName
* @param money
*/
public Money(int id, String userName, int money) {
super();
this.id = id;
this.userName = userName;
this.money = money;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package com.panli.dao;
/**
* 借錢與收錢為一個事務處理事件單元的JDBC程式碼
*/
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;
import com.panli.dbutil.DbUtil;
import com.panli.model.Money;
public class UserMoneyOutInDao {
private static DbUtil dbUtil = new DbUtil();
/**
* 借出錢給他人方
* @param money
* @return
* @throws Exception
*/
private static int OutMoney(Money money)throws Exception{
Connection conn = dbUtil.getCon();
String sql = "update t_money set money=money-? where id = ? ";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, money.getMoney());
pstmt.setInt(2, money.getId());
int result = pstmt.executeUpdate();
dbUtil.close(pstmt, conn);
return result;
}
/**
* 借到錢的一方
* @param money
* @return
* @throws Exception
*/
private static int InMoney(Money money)throws Exception{
Connection conn = dbUtil.getCon();
String sql = "update t_money set money=money+? where id = ? ";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, money.getMoney());
pstmt.setInt(2, money.getId());
int result = pstmt.executeUpdate();
dbUtil.close(pstmt, conn);
return result;
}
public static void main(String[] args) {
int moneys = 10;
Money Age = new Money(1, moneys);
Money Bge = new Money(2, moneys);
Connection conn1 = null;
Savepoint sp = null;
try {
conn1 = dbUtil.getCon();
//取消自動提交事務
conn1.setAutoCommit(false);
//設定事務儲存點,如果發生錯誤則回滾到此處
sp = conn1.setSavepoint();
//Age借出錢給Bge
OutMoney(Age);
System.out.println("Age借錢成功!");
//Bge收到錢
InMoney(Bge);
System.out.println("Bge收到錢成功!");
} catch (Exception e) {
// TODO Auto-generated catch block
try {
//如果遇到錯誤就回滾
conn1.rollback(sp);
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Age借錢失敗!");
System.out.println("Bge收到錢失敗!");
e.printStackTrace();
}finally{
try {
//如果事務操作成功,提交事務
conn1.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//關閉連線
conn1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("錢財交易成功!");
}
}