1

我有一个 jdbc 代码,其中我在代码中使用了事务管理。以下是代码。我正在使用 Mysql 数据库。

public class JdbcConn {
public static void main(String[] args){
    Savepoint spt1 = null;
    Connection con = null;
    try{
        Class.forName("org.gjt.mm.mysql.Driver");
        con = DriverManager.getConnection("jdbc:mysql://localhost","root","tany");
        con.setAutoCommit(false);
         spt1= con.setSavepoint("svpt1");

        PreparedStatement psmt;
        String query1 = "select city, countryid from querytest.city;";
        psmt=con.prepareStatement(query1);
        ResultSet rs=psmt.executeQuery();
        while(rs.next()){
            String query2 = "insert into sun.city (city,countryid) values('"+rs.getString(1)+"',"+rs.getInt(2)+");";
            psmt=con.prepareStatement(query2);
            psmt.executeUpdate();
        }
        String query3 = "create database `transtest`;";
        psmt=con.prepareStatement(query3);
        psmt.executeUpdate();

        String query4 = "CREATE TABLE `transtest`.`trans` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY  (`id`)) ENGINE=MyISAM;";                
        psmt=con.prepareStatement(query4);
        psmt.executeUpdate();


        String query5 = "CREATE TABLE `transtest`.`transone` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY  (`id`)) ENGINE=MyISAM;";                
        psmt=con.prepareStatement(query5);
        psmt.executeUpdate();


        String query6 = "CREATE TABLE `transtest`.`transtwo` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY  (`id`)) ENGINE=MyISAM;";                
        psmt=con.prepareStatement(query6);
        psmt.executeUpdate();

        for(int i=1;i<=10;i++){
            String query7 = "insert into `transtest`.`transtwo` (`val`) values ("+i*2+");";                
            psmt=con.prepareStatement(query7);
            psmt.executeUpdate();
        }

        String query8 = "insertd into `transtest`.`trans` (`val`) values (500);";                
        psmt=con.prepareStatement(query8);
        psmt.executeUpdate();
        JOptionPane.showMessageDialog(null, "Process completed!");
        con.commit();
        con.setAutoCommit(true);

    }catch(SQLException sqle){
        try {
            con.rollback(spt1);
            JOptionPane.showMessageDialog(null, "Rollback1!");
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        sqle.getMessage();
        sqle.printStackTrace();
    }catch (ClassNotFoundException cnfe) {
        // TODO Auto-generated catch block
        try {
            con.rollback(spt1);
            JOptionPane.showMessageDialog(null, "Rollback2!");
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        cnfe.getMessage();
        cnfe.printStackTrace();
    }catch (Exception e) {
        // TODO Auto-generated catch block
        try {
            con.rollback(spt1);
            JOptionPane.showMessageDialog(null, "Rollback3!");
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        e.getMessage();
        e.printStackTrace();
    }

}   

}

当 sql 异常出现时,上面的代码不会回滚。query1 中表的架构和 query2 中表的架构相同,但正如您所见,数据库不同。

我只是不知道是否有任何异常出现,为什么它不回滚查询从 query2 到 query7 所做的更改。

我在 query8 中故意犯了一个句法错误作为例外。

请在这个问题上指导我的朋友,并请让我知道我在代码中的错误。

谢谢你!

4

2 回答 2

5

这是我的做法:

Connection con = null;
boolean ok = false;
try {
    con = DriverManager.getConnection(...);
    ...
    con.commit();
    ok = true;
} catch (...) {
    // diagnose exception 
} 
...
} finally {
    if (con != null) {
        try {
            if (!ok) con.rollback();
        } finally {
           con.close();
        }
    }
}

换句话说,在 finally 块中关闭连接并回滚......并且不要重复代码。

并且不要抓住Exception......见下文。


对问题的评论说:

作为一般原则,捕获 Throwable,而不仅仅是 Exception。实际上,catch 只是 Throwable,不需要重复积木。这甚至可以解决你的问题。

捕获Exception,尤其Throwable是一个坏主意,除非处理异常后的下一个操作是退出应用程序。可能会发生许多潜在的未经检查的异常/错误。您无法知道意外异常的原因是什么,或者应用程序是否可以安全地恢复。


但是我的代码中的问题是它没有将查询完成的事务从 query2 回滚到 query7

可能是因为其中一些语句是非事务性的(例如 CREATE TABLE),并且执行非事务性语句会导致当前事务自动提交。

可能是旧版本的 MySQL 和您使用的 JDBC 驱动程序有问题。“org.gjt.mm.mysql”驱动程序真的很旧,而且我知道早期版本的 MySQL 根本不支持事务。


正如我所怀疑的,您不能在 MySQL 中回滚 CREATE TABLE。

来源:

于 2012-04-19T12:22:20.383 回答
3

您不能在 MySQL 中回滚 create table 语句,因为它会导致隐式提交。请参阅:导致隐式提交的语句

于 2012-04-19T12:48:29.253 回答