Posted on 2009-12-28 21:22
啥都寫點 閱讀(4198)
評論(0) 編輯 收藏 所屬分類:
J2SE

事務在提交前,所有的操作都是在虛擬的環(huán)境中進行的,事務提交時才將事務進行的所有修改更新到數(shù)據(jù)庫的存儲介質(zhì)上,如硬盤。在事務提交前,如果有操作失敗的情況,那么需要進行回滾操作,便可以取消事務所進行的修改,當事務被提交后,再執(zhí)行回滾是無效的。

事務需要數(shù)據(jù)庫的支持,不是所有的數(shù)據(jù)庫都執(zhí)行事務,如MySQL中默認的數(shù)據(jù)庫都采用了MyISAM存儲引擎,它不支持事務,如果MySQL數(shù)據(jù)庫采用InnoDB存儲的引擎,便支持事務。通過DatabaseMetaData的supportsTransactions方法可以判斷數(shù)據(jù)庫是否支持事務。

數(shù)據(jù)庫連接Connection對象默認是自動提交的,即在該連接下,每用Statement執(zhí)行一條SQL語句,便提交到數(shù)據(jù)庫。為了控制事務提交的時機,需要在事務開始前,調(diào)用Connection的setAutoCommit方法將數(shù)據(jù)庫連接的自動提交屬性關閉,此后,所有的操作都不會提交到數(shù)據(jù)庫,直到調(diào)用Connection的commit方法,提交事務位置。

在提交事務之前,一旦有SQL語句執(zhí)行不通過,應調(diào)用Connection的rollback方法,執(zhí)行回滾操作,那么此前所有數(shù)據(jù)庫操作將無效。

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


/** *//**
* 判斷數(shù)據(jù)庫是否支持事務,如果支持,如何實現(xiàn)事務的提交與回滾。
* MySQL中如果要使用事物,必須使用InnoDB存儲引擎,在創(chuàng)建表時,后面加上ENGINE=InnoDB。
* MySQL默認的存儲引擎是MyISAM,不支持事物
*/

public class Transaction
{


/** *//**
* 判斷數(shù)據(jù)庫是否支持事務
* @param con 數(shù)據(jù)庫的連接
* @return
*/

public static boolean supportTransaction(Connection con)
{

try
{
// 得到數(shù)據(jù)庫的元數(shù)據(jù)
DatabaseMetaData md = con.getMetaData();
return md.supportsTransactions();

} catch (SQLException e)
{
e.printStackTrace();
}
return false;
}

/** *//**
* 將一組SQL語句放在一個事務里執(zhí)行,要某全部執(zhí)行通過,要某全部不執(zhí)行
* @param con 數(shù)據(jù)庫的連接
* @param sqls 待執(zhí)行的SQL數(shù)組
*/

public static void goTransaction(Connection con, String[] sqls)
{

if (sqls == null)
{
return ;
}
Statement sm = null;

try
{
// 事務開始
System.out.println("事務開始!");
// 設置連接不自動提交,即用該連接進行的操作都不更新到數(shù)據(jù)庫
con.setAutoCommit(false);
sm = con.createStatement();

for (int i=0; i<sqls.length; i++)
{
// 執(zhí)行SQL語句,但是沒更新到數(shù)據(jù)庫
sm.execute(sqls[i]);
}
// 提交,立即更新到數(shù)據(jù)庫
System.out.println("事務提交!");
con.commit();
System.out.println("事務結束!");
// 事務結束

} catch (SQLException e)
{

try
{
// 出現(xiàn)異常時,進行回滾,取消前面執(zhí)行的操作
System.out.println("事務執(zhí)行失敗,進行回滾!");
con.rollback();

} catch (SQLException e1)
{
e1.printStackTrace();
}

} finally
{
OperateDB.closeStatement(sm);
}
}
public static void main(String[] args) throws ClassNotFoundException,

SQLException
{
String dbName = "studentdb";
String userName = "test";
String password = "test";
String[] sqls = new String[3];
sqls[0] = "UPDATE student_basic_innodb SET score=93 where name='john'";
sqls[1] = "INSERT INTO student_basic_innodb (name, age, score)"
+ " VALUES ('zhangsan', 17, 86)";
// 執(zhí)行這條語句會引起錯誤,因為表student_basic_innodb沒有xxxxxxx列
sqls[2] = "DELETE FROM student_basic_innodb where xxxxxxx='wade'";
Connection con = null;

try
{
// 獲得數(shù)據(jù)庫連接
con = DBConnector.getMySQLConnection(null, null, null, dbName,
userName, password);
// 判斷是否支持批處理
boolean supportTransaction = Transaction.supportTransaction(con);
System.out.println("支持事務? " + supportTransaction);

if (supportTransaction)
{
// 執(zhí)行事務
Transaction.goTransaction(con, sqls);
}

} catch (ClassNotFoundException e1)
{
throw e1;

} catch (SQLException e2)
{
throw e2;

} finally
{
// 關閉數(shù)據(jù)庫連接
OperateDB.closeConnection(con);
}
}
} --
學海無涯