有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JDBC Informix事务回滚

在一个maven项目中,我连接到一个informix数据库,我想在异常发生时进行回滚。 informix似乎不支持回滚,我收到了以下异常

java.sql.SQLException: Not in transaction.
    at com.informix.util.IfxErrMsg.buildExceptionWithMessage(IfxErrMsg.java:416)
    at com.informix.util.IfxErrMsg.buildIsamException(IfxErrMsg.java:401)
    at com.informix.jdbc.IfxSqli.addException(IfxSqli.java:3096)
    at com.informix.jdbc.IfxSqli.receiveError(IfxSqli.java:3368)
    at com.informix.jdbc.IfxSqli.dispatchMsg(IfxSqli.java:2292)
    at com.informix.jdbc.IfxSqli.receiveMessage(IfxSqli.java:2217)
    at com.informix.jdbc.IfxSqli.executeRollback(IfxSqli.java:646)
    at com.informix.jdbc.IfxSqliConnect.rollback(IfxSqliConnect.java:2124)
    at com.company.helpers.DBDriver.makeConnection(DBDriver.java:72)
    at com.company.Main.main(Main.java:40)

下面是有问题的片段。调用connection.rollback()时发生异常。出于测试目的,我在try子句上调用了rollback

     try{
        connection = DriverManager.getConnection(this.url,this.username,this.password);
        LOGGER.info("Database connection successful.");
        statement = connection.createStatement();
        resultSet = statement.executeQuery("select FIRST 10 * from clients");
        while (resultSet.next()) {
            System.out.println(resultSet.getString("id") + ", " + resultSet.getString("name"));
        }

        String sql = "UPDATE clients\n" +
                "\tSET idhost=5\n" +
                "\tWHERE id=9058;\n";
        statement.executeUpdate(sql);
        connection.rollback(); //temporary to test rollback() 
        //connection.commit();

      }
      catch (Exception e) {
        //connection.rollback();
        LOGGER.error("Errors occurred in database.");
        LOGGER.error(e.getMessage(), e);

      }

共 (2) 个答案

  1. # 1 楼答案

    Informix有4种类型的数据库:

    • 未锁定
    • 缓冲记录
    • 无缓冲测井
    • (无缓冲记录和)模式ANSI

    未标记的数据库不支持事务。可能是您已连接到未标记的数据库。在执行BEGIN WORK(或just BEGIN)之前,缓冲和非缓冲日志数据库不会启动事务。您可能会失败,因为您没有显式启动事务。模式ANSI数据库自动启动事务并保持它们打开,直到显式提交或回滚,或者会话终止,在这种情况下,事务被回滚。您始终可以在模式ANSI数据库中回滚(或提交)

    JDBC标准可能需要“MODE ANSI”语义。它们不难模仿——驱动程序只需在适当的点发送“开始工作”

    ……嗯

    在异常堆栈跟踪的顶部,它表示“不在事务中”。这是错误-255;还有一个错误-256“事务不可用”。如果您连接到一个未标记的数据库,您将得到-256。由于得到-255,您必须连接到已记录的数据库,但您没有显式启动事务,因此无法回滚。在没有BEGIN后跟COMMIT或ROLLBACK的情况下,每条语句都是一个自包含事务

    要修复此问题,您需要启动一个事务。这可能很简单:
    Statement st = connection.createStatement;
    int count = st.executeUpdate("BEGIN WORK");
    st.close();
    

    或者可以使用“立即执行”选项。代码未经测试;我不是JDBC程序员,也没有测试JDBC代码的设置。

    分析基本正确。建议的解决方案并非如此。有关{}的讨论,请参见{a1}by{a2},它提供了解决问题的正确方法

  2. # 2 楼答案

    这实际上是使用JDBC自动提交时的预期行为。Informix JDBC驱动程序默认启用了自动提交。看见 https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html来简单介绍一下

    因此,您执行的每个语句都会自动提交。JDBC基本上为每个查询和/或语句执行BEGIN-WORK、EXECUTE、COMMIT-WORK

    因此,当您显式执行connection.rollback()时,它将失败,因为您的所有语句都已提交,而且从技术上讲,您不在事务中

    您可以使用connection.setAutoCommit(false)关闭此功能,然后可以发出SQL语句"BEGIN WORK"来启动事务,并connection.rollback()来回滚事务

    正如Jonathan所指出的,另一个怪癖是使用ANSI兼容的数据库而不是普通的日志数据库。如果是ANSI,则不需要“BEGIN WORK”,因为ANSI数据库始终位于事务中,并且会为您启动一个新的事务

    通常,如果要处理事务,必须关闭自动提交