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 のテーブルのスキーマは同じですが、ご覧のとおり、データベースは異なります。

クエリによって行われた変更をクエリ2からクエリ7にロールバックしない理由で例外が発生するかどうかはわかりません。

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();
        }
    }
}

つまり、最終ブロックで接続を閉じてロールバックし、コードを繰り返さないでください。

そして、キャッチしExceptionないでください...以下を参照してください。


質問に対するコメントには次のように書かれています。

原則として、Exception だけでなく、Throwable もキャッチします。実際、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 に答える