Cyh的博客

Email:kissyan4916@163.com
posts - 26, comments - 19, trackbacks - 0, articles - 220

提交与回滚事务

Posted on 2009-12-28 21:22 啥都写点 阅读(4189) 评论(0)  编辑  收藏 所属分类: J2SE
     事务在提交前,所有的操作都是在虚拟的环境中进行的,事务提交时才将事务进行的所有修改更新到数据库的存储介质上,如硬盘。在事务提交前,如果有操作失败的情况,那么需要进行回滚操作,便可以取消事务所进行的修改,当事务被提交后,再执行回滚是无效的。
     事务需要数据库的支持,不是所有的数据库都执行事务,如MySQL中默认的数据库都采用了MyISAM存储引擎,它不支持事务,如果MySQL数据库采用InnoDB存储的引擎,便支持事务。通过DatabaseMetaData的supportsTransactions方法可以判断数据库是否支持事务。
     数据库连接Connection对象默认是自动提交的,即在该连接下,每用Statement执行一条SQL语句,便提交到数据库。为了控制事务提交的时机,需要在事务开始前,调用Connection的setAutoCommit方法将数据库连接的自动提交属性关闭,此后,所有的操作都不会提交到数据库,直到调用Connection的commit方法,提交事务位置。
     在提交事务之前,一旦有SQL语句执行不通过,应调用Connection的rollback方法,执行回滚操作,那么此前所有数据库操作将无效。


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

/**
 * 判断数据库是否支持事务,如果支持,如何实现事务的提交与回滚。
 * MySQL中如果要使用事物,必须使用InnoDB存储引擎,在创建表时,后面加上ENGINE=InnoDB。
 * MySQL默认的存储引擎是MyISAM,不支持事物
 
*/

public class Transaction {

    
/**
     * 判断数据库是否支持事务
     * 
@param con    数据库的连接
     * 
@return
     
*/

    
public static boolean supportTransaction(Connection con){
        
try {
            
// 得到数据库的元数据
            DatabaseMetaData md = con.getMetaData();
            
return md.supportsTransactions();
        }
 catch (SQLException e) {
            e.printStackTrace();
        }

        
return false;
    }

    
    
/**
     * 将一组SQL语句放在一个事务里执行,要某全部执行通过,要某全部不执行
     * 
@param con    数据库的连接
     * 
@param sqls    待执行的SQL数组
     
*/

    
public static void goTransaction(Connection con, String[] sqls){
        
if (sqls == null){
            
return ;
        }

        Statement sm 
= null;
        
try {
            
// 事务开始
            System.out.println("事务开始!");
            
// 设置连接不自动提交,即用该连接进行的操作都不更新到数据库
            con.setAutoCommit(false);
            sm 
= con.createStatement();
            
for (int i=0; i<sqls.length; i++){
                
// 执行SQL语句,但是没更新到数据库
                sm.execute(sqls[i]);
            }

            
// 提交,立即更新到数据库
            System.out.println("事务提交!");
            con.commit();
            System.out.println(
"事务结束!");
            
// 事务结束
        }
 catch (SQLException e) {
            
try {
                
// 出现异常时,进行回滚,取消前面执行的操作
                System.out.println("事务执行失败,进行回滚!");
                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)";
        
// 执行这条语句会引起错误,因为表student_basic_innodb没有xxxxxxx列
        sqls[2= "DELETE FROM student_basic_innodb where xxxxxxx='wade'";
        
        Connection con 
= null;
        
try {
            
// 获得数据库连接
            con = DBConnector.getMySQLConnection(nullnullnull, dbName,
                    userName, password);
            
// 判断是否支持批处理
            boolean supportTransaction = Transaction.supportTransaction(con);
            System.out.println(
"支持事务? " + supportTransaction);
            
if (supportTransaction){
                
// 执行事务
                Transaction.goTransaction(con, sqls);
            }

        }
 catch (ClassNotFoundException e1) {
            
throw e1;
        }
 catch (SQLException e2) {
            
throw e2;
        }
 finally {
            
// 关闭数据库连接
            OperateDB.closeConnection(con);
        }

    }

}


                                                                                                       --    学海无涯