JDBC例子4_事務管理
事務管理
1 事務概述
事務指的是邏輯上的一組操作(多條sql語句),組成這組操作的各個單元要麼全都成功,要麼全都失敗.
事務作用:保證在一個事務中多次操作要麼全都成功,要麼全都失敗.
例如轉賬:
update account set money=money-100 where name='tom';//tom轉出100塊
update account set money=money+100 where name='jerry';//jerry收到100塊
以上兩條sql語句,很明顯是一組語句,因為轉賬要麼都成功要麼都失敗,不應該出現一方成功另一方失敗的情況.那麼我們就需要把他們看成一個事務.
事務處理
事務處理:保證所有事務都作為一個工作單元來執行,即使出現了故障,都不能改變這種執行方式。當在一個事務中執行多個操作時,要麼所有的事務都被提交(commit),要麼整個事務回滾(rollback)到最初狀態
當一個連線物件被建立時,預設情況下是自動提交事務:每次執行一個 SQL 語句時,如果執行成功,就會向資料庫自動提交,而不能回滾。
事務開始於:
• 連線到資料庫上,並執行一條DML語句(INSERT、UPDATE或DELETE)。
• 前一個事務結束後,又輸入了另外一條DML語句。
事務結束於:
• 執行COMMIT或ROLLBACK語句。
• 執行一條DDL語句,例如CREATE TABLE語句;在這種情況下,會自動執行COMMIT語句。
• 執行一條DCL語句,例如GRANT語句;在這種情況下,會自動執行COMMIT語句。
• 斷開與資料庫的連線。
• 執行了一條DML語句,該語句卻失敗了;在這種情況中,會為這個無效的DML語句執行ROLLBACK語句。
事務特性
原子性:強調事務的不可分割.多條語句要麼都成功,要麼都失敗。
一致性:強調的是事務的執行的前後,資料要保持一致.
隔離性:一個事務的執行不應該受到其他事務的干擾.
永續性:事務一旦結束(提交/回滾)資料就持久保持到了資料庫.
2 使用JDBC原生的API進行事務管理
為了讓多個 SQL 語句作為一個事務執行:
呼叫 Connection 物件的 setAutoCommit(false); 以取消自動提交事務
在所有的 SQL 語句都成功執行後,呼叫 commit(); 方法提交事務
在出現異常時,呼叫 rollback(); 方法回滾事務
若此時 Connection 沒有被關閉, 則需要恢復其自動提交狀態
#建立賬號表
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
package cn.njit.aff;
/****
* 使用jdbc實現事務
*
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Testjdbc {
public static void main(String[] args) {
Connection conn=getConnection();
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}//設定成不自動提交
String sql="Update account set money=money-? where name=?";
PreparedStatement psmt;
try {
psmt=conn.prepareStatement(sql);
psmt.setDouble(1, 500);
psmt.setString(2, "螺紋");
psmt.executeUpdate();
System.out.println("----");
//-------------------
int x=1/0;
//製造異常,引起回滾
//-------------------
sql="update account set money=money+? where name=?";
psmt=conn.prepareStatement(sql);
psmt.setDouble(1, 500);
psmt.setString(2, "劉智偉");
psmt.executeUpdate();
System.out.println("----");
conn.commit();
} catch (SQLException e) {
try {
System.out.println("======");
e.printStackTrace();
conn.rollback();
}catch(SQLException e1) {
e1.printStackTrace();
}
}finally {
if(null!=conn) {
try{
conn.close();
}catch (SQLException e2){
e2.printStackTrace();
}
}
}
}
public static Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String url="jdbc:mysql://localhost:3306/njit?useUnicode=true&characterEncoding=utf-8";
String name="root";
String password="admin";
Connection conn = null;
try {
conn=DriverManager.getConnection(url, name, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
3 使用DBUtils實現事務管理
要點:
QueryRunner qr = new QueryRunner();//為了支援事務,不能傳遞連線池
conn = C3P0Utils02.getConnection(); //獲取jdbc原生連線
conn.setAutoCommit(false); //開啟事務
conn.commit(); //正常,則提交事務
conn.rollback(); //異常或者業務不正確,則回滾
Conn.close(); //最後關閉事務
package cn.njit.aff;
/****
* 使用DBUtils實現事務
*/
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import util.C3P0Utils;
public class TestDBUtils {
public static void main(String[] args) {
testUpdate();
}
static void testUpdate() {
QueryRunner qr = new QueryRunner();
// 不能直接把conn放進去
Connection conn = null;
try {
conn = C3P0Utils.getConnection();
System.out.println("0");
} catch (SQLException e) {
e.printStackTrace();
}
try {
conn.setAutoCommit(false);
String sql = "Update account set money=money-? where name=?";
Object[] o = { 500, "劉智偉" };
qr.update(conn, sql, o);
System.out.println("1");
// ---------------
int x=1/0;
// ---------------
String str = "update account set money=money+? where name=?";
Object[] o2 = { 500, "螺紋" };
qr.update(conn, str, o2);
System.out.println("2");
conn.commit();
} catch (SQLException e) {
try {
System.out.println("===========");
conn.rollback();
e.printStackTrace();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
if (null != conn) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}