3

我有一个 JDBC 代码,其中有多个Savepoints;像这样的东西:

1st insert statement
2nd insert statement
savepoint = conn.setSavepoint("S1");
1st insert statement
2nd update statement
savepoint = conn.setSavepoint("S2");
1st delete statement
2nd delete statement
savepoint = conn.setSavepoint("S3");
1st insert statement
2nd delete statement
savepoint = conn.setSavepoint("S4");

现在在 catch 块中,我正在捕获异常并检查是否Savepoint存在null;如果是,则回滚整个连接,否则回滚到Savepoint. 但我无法理解Savepoint我应该回滚到哪个位置。

如果我将所有保存点名称更改为 "S1" 会好吗?在那种情况下,我将如何理解有多少直到Savepoint正确工作?

请告知如何理解直到Savepoint正确执行了哪些工作?

4

2 回答 2

3

会将其视为多笔交易。因此,您可以使用多个 try/catch 块来处理这个问题。您似乎还覆盖了保存点对象,因此回滚是不可行的。

更多信息。JDBC 还支持设置保存点,然后回滚到指定的保存点。以下方法可用于定义保存点。

SavePoint savePoint1 = connection.setSavePoint();

使用带有参数的回滚调用将事务回滚到已定义的保存点。

connection.rollback(savePoint1);

参考。 http://www.sourcetricks.com/2014/08/jdbc-handling-transactions.html

于 2014-08-03T11:26:47.073 回答
3

在这种情况下,我发现棘手的部分是确保仅在所有插入成功时才提交事务,但如果任何插入失败则回滚所有更新。我使用保存点堆栈来处理这种情况。高度简化的代码如下:

连接包装类:

public class MyConnection {
    Connection conn;
    static DataSource ds;
    Stack<Savepoint> savePoints = null;

    static {
        //... stuff to initialize datasource.
    }

    public MyConnection() {
        conn = ds.getConnection();
    }

    public void beginTransaction() {
        if (savePoints == null) {
            savePoints = new Stack<Savepoint>();
            conn.setAutoCommit(false);
            conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
        } else {
            savePoints.push(conn.setSavepoint());
        }
    }

    public void commit() throws SQLException {
        if (savePoints == null || savePoints.empty()) {
            conn.commit();
        } else {
            Savepoint sp = savePoints.pop();
            conn.releaseSavepoint(sp);
        }
    }

    public void rollback() throws SQLException {
        if (savePoints == null || savePoints.empty()) {
            conn.rollback();
        } else {
            Savepoint sp = savePoints.pop();
            conn.rollback(sp);
        }
    }

    public void releaseConnection() {
        conn.close();
    }
}

然后,您可以拥有可以独立或组合调用的各种方法。在下面的示例中,methodA 可以单独调用,也可以作为调用 methodB 的结果。

public class AccessDb {

    public void methodA(MyConnection myConn) throws Exception {
        myConn.beginTransaction();
        try {
            // update table A
            // update table B
            myConn.commit();
        } catch (Exception e) {
            myConn.rollback();
            throw e;
        } finally {

        }
    }

    public void methodB(MyConnection myConn) throws Exception {
        myConn.beginTransaction();
        try {
            methodA(myConn);
            // update table C
            myConn.commit();
        } catch (Exception e) {
            myConn.rollback();
            throw e;
        } finally {

        }
    }
}

这样,如果出现任何问题,它会完全回滚(作为异常处理的结果),但它只会提交整个事务,而不是提交部分完成的事务。

于 2014-12-28T20:08:32.543 回答