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);
}
# 1 楼答案
Informix有4种类型的数据库:
未标记的数据库不支持事务。可能是您已连接到未标记的数据库。在执行BEGIN WORK(或just BEGIN)之前,缓冲和非缓冲日志数据库不会启动事务。您可能会失败,因为您没有显式启动事务。模式ANSI数据库自动启动事务并保持它们打开,直到显式提交或回滚,或者会话终止,在这种情况下,事务被回滚。您始终可以在模式ANSI数据库中回滚(或提交)
JDBC标准可能需要“MODE ANSI”语义。它们不难模仿——驱动程序只需在适当的点发送“开始工作”
……嗯
在异常堆栈跟踪的顶部,它表示“不在事务中”。这是错误-255;还有一个错误-256“事务不可用”。如果您连接到一个未标记的数据库,您将得到-256。由于得到-255,您必须连接到已记录的数据库,但您没有显式启动事务,因此无法回滚。在没有BEGIN后跟COMMIT或ROLLBACK的情况下,每条语句都是一个自包含事务
要修复此问题,您需要启动一个事务。这可能很简单:或者可以使用“立即执行”选项。代码未经测试;我不是JDBC程序员,也没有测试JDBC代码的设置。
分析基本正确。建议的解决方案并非如此。有关{}的讨论,请参见{a1}by{a2},它提供了解决问题的正确方法
# 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数据库始终位于事务中,并且会为您启动一个新的事务通常,如果要处理事务,必须关闭自动提交