On a maven project I am connecting to an informix database and I want to make a rollback when an exceptions occurs. It seems that informix doesn't support rollback and I receive the following exception.
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)
And here is the snippet in question. The exception occurs when calling connection.rollback()
. For testing purposes, I called rollback
on try
clause.
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);
}
This is actually expected behavior when using JDBC autocommit. The Informix JDBC driver has auto-commit enabled by default. See https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html for a brief introduction to this.
So each statement you execute is automatically committed. The JDBC essentially executes a BEGIN WORK, EXECUTE, COMMIT WORK for each query and/or statement.
Thus when you explicitly execute a connection.rollback()
, it will fail because all of your statements have been committed and you are technically not in a transaction.
You can turn this off with connection.setAutoCommit(false)
then you can issue SQL statement "BEGIN WORK"
to start a transaction and connection.rollback()
to roll it back.
As Jonathan notes another quirk is if you use ANSI compatible database versus a normal logged database. If it is ANSI, then you don't need the "BEGIN WORK
" because ANSI databases are always in a transaction and a new one is started for you.
In general if you want to work with transactions you have to turn off auto-commit.