Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我们什么时候需要调用java.sql.Connection.rollback()?_Java_Jdbc - Fatal编程技术网

我们什么时候需要调用java.sql.Connection.rollback()?

我们什么时候需要调用java.sql.Connection.rollback()?,java,jdbc,Java,Jdbc,我必须在一个函数中修改几个表。他们必须全部成功,否则全部失败。如果一个操作失败,我希望所有操作都失败。我有以下资料: public void foo() throws Exception { Connection conn = null; try { conn = ...; conn.setAutoCommit(false); grok(conn); conn.commit(); } catch (E

我必须在一个函数中修改几个表。他们必须全部成功,否则全部失败。如果一个操作失败,我希望所有操作都失败。我有以下资料:

public void foo() throws Exception {
    Connection conn = null;
    try {
        conn = ...;
        conn.setAutoCommit(false);
        grok(conn);
        conn.commit();
    }
    catch (Exception ex) {
        // do I need to call conn.rollback() here?
    }
    finally {
        if (conn != null) {
            conn.close();
            conn = null;
        }
    }
}

private void grok(Connection conn) throws Exception {
    PreparedStatement stmt = null;
    try {
        // modify table "apple" 
        stmt = conn.prepareStatement(...);
        stmt.executeUpdate();
        stmt.close();

        // modify table "orange"
        stmt = conn.prepareStatement(...);
        stmt.executeUpdate();
        stmt.close();

        ...
    }
    finally {
        if (stmt != null) {
            stmt.close();
        }
    }
}
我想知道,如果在此过程中出现问题,是否需要调用rollback()

其他信息:我正在使用连接池。在上面的示例中,我还确保使用finally语句来关闭每个PreparedStatement,只是为了简洁起见


谢谢

您不需要调用
rollback()
。如果连接在未完成
commit()
的情况下关闭,它将回滚


您也不需要将
conn
设置为
null
;由于
try
块在
conn
初始化后启动(假设
..
的计算结果不能为空),因此您不需要
!=在
finally
中为空。

如果调用“提交”,则事务将被提交。如果有多个insert/update语句,但其中一个语句失败,则提交将导致未提交到数据库的insert/update语句失败。因此,是的,如果不希望其他语句提交到db,则需要调用rollback。通过将autocommit设置为false,您实际上可以同时提交或回滚多个语句。否则,每个语句将自动提交

是的,如果任何语句失败或在调用commit之前检测到异常,则需要调用rollback。这是一篇老文章,但公认的答案是错误的。您可以自己尝试,在提交之前抛出一个异常,并观察如果不手动回滚,您的插入仍然会进入数据库

JDBC文档

文档中的正确用法示例

public void updateCoffeeSales(HashMap salesForWeek)
抛出SQLException{
PreparedStatement updateSales=null;
PreparedStatement updateTotal=null;
字符串更新字符串=
更新“+dbName+”.coffes”+
“设置销售额=?其中COF_NAME=?”;
字符串更新语句=
更新“+dbName+”.coffes”+
“设置总计=总计+?”+
“其中COF_NAME=?”;
试一试{
con.setAutoCommit(假);
updateSales=con.prepareStatement(updateString);
updateTotal=con.prepareStatement(updateStatement);
对于(Map.Entry e:salesForWeek.entrySet()){
updateSales.setInt(1,e.getValue().intValue());
setString(2,例如getKey());
updateSales.executeUpdate();
updateTotal.setInt(1,e.getValue().intValue());
setString(2,例如getKey());
updateTotal.executeUpdate();
con.commit();
}
}捕获(SQLE异常){
jdbcttutorialutilities.printSQLException(e);
如果(con!=null){
试一试{
系统错误打印(“事务正在回滚”);
con.rollback();
}捕获(SQLException例外){
JDBCTutorialUtilities.printSQLException(excep);
}
}
}最后{
if(updateSales!=null){
updateSales.close();
}
if(updateTotal!=null){
updateTotal.close();
}
con.setAutoCommit(真);
}
}

为了澄清我的答案,这假设您将有多个语句。在您的示例中,如果只有一条语句,那么它将自动回滚。但是如果在Java代码中调用了多个语句,那么您可能希望回滚。我更新了以显示有多个语句(变量被重用)-我仍然需要回滚吗?谢谢你应该防御性地编码。上面的代码将使用单个连接,您不需要显式调用rollback。但是,如果您将该代码放入一个有连接池的环境中,那么当其他事务重用同一个连接时,您肯定会遇到奇怪的行为,因为池中的连接通常从不关闭。就我个人而言,我会一直使用回滚,除非您能够确定它会导致性能下降(回滚非常昂贵),并且您完全了解您所处环境的事务行为。Ok更新了示例以反映conn可能为空,因此即使进行了更新,我仍然不需要调用rollback()?谢谢你,你不需要叫rollback。您前面的示例中,
conn
try
之前就已初始化。这根本不是真的。您必须在连接上调用rollback以使更改回滚。它们不会自动为您回滚。看到我的答案了,但是在调用commit之前抛出一个异常很容易测试自己。嗨@UsmanMutawakil那么如果你既不
commit
也不
rollback
,会发生什么呢?@可悲的Hello。如果既不提交也不回滚插入,则插入将被持久化,但它们是否可以读取将取决于您使用的事务隔离级别。在我的例子中,我可以看到数据“脏读”。驱动程序和数据库使用设置的事务隔离级别,但通过显式回滚,问题解决了一半。
public void updateCoffeeSales(HashMap<String, Integer> salesForWeek)
    throws SQLException {

    PreparedStatement updateSales = null;
    PreparedStatement updateTotal = null;

    String updateString =
        "update " + dbName + ".COFFEES " +
        "set SALES = ? where COF_NAME = ?";

    String updateStatement =
        "update " + dbName + ".COFFEES " +
        "set TOTAL = TOTAL + ? " +
        "where COF_NAME = ?";

    try {
        con.setAutoCommit(false);
        updateSales = con.prepareStatement(updateString);
        updateTotal = con.prepareStatement(updateStatement);

        for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) {
            updateSales.setInt(1, e.getValue().intValue());
            updateSales.setString(2, e.getKey());
            updateSales.executeUpdate();
            updateTotal.setInt(1, e.getValue().intValue());
            updateTotal.setString(2, e.getKey());
            updateTotal.executeUpdate();
            con.commit();
        }
    } catch (SQLException e ) {
        JDBCTutorialUtilities.printSQLException(e);
        if (con != null) {
            try {
                System.err.print("Transaction is being rolled back");
                con.rollback();
            } catch(SQLException excep) {
                JDBCTutorialUtilities.printSQLException(excep);
            }
        }
    } finally {
        if (updateSales != null) {
            updateSales.close();
        }
        if (updateTotal != null) {
            updateTotal.close();
        }
        con.setAutoCommit(true);
    }
}