简体   繁体   中英

Reason for java.sql.SQLException “database in auto-commit mode”

I use sqlite database and java.sql classes in servlet application to batch-insert some data into database. There are consecutive four inserts of different kinds of data. Each one looks like this:

PreparedStatement statement = conn
    .prepareStatement("insert or ignore into nodes(name,jid,available,reachable,responsive) values(?,?,?,?,?);");
for (NodeInfo n : nodes)
{
    statement.setString(1, n.name);
    statement.setString(2, n.jid);
    statement.setBoolean(3, n.available);
    statement.setBoolean(4, n.reachable);
    statement.setBoolean(5, n.responsive);
    statement.addBatch();
}

conn.setAutoCommit(false);
statement.executeBatch();
conn.commit();
conn.setAutoCommit(true);
statement.close();

But sometimes I get the

java.sql.SQLException: database in auto-commit mode

I found in source code of java.sql.Connection that this exception is thrown when calling commit() while database is in autocommit mode. But I turn autocommit off before and I can't see any place for some parallel execution related issues as for now application is only turned on once.

Do you have any idea how to debug this issue? Maybe there's some other reason for this error (because I just found that exception about database not found or not well configured can be thrown when inserting null into non-null field)?.

May be an issue is with order of statements. Your database statement should be :

  PreparedStatement statement1 = null;
  PreparedStatement statement2 = null;
  Connection connection=null;

    try {
        //1. Obtain connection and set `false` to autoCommit
        connection.setAutoCommit(false);
        //2. Prepare and execute statements
        statement1=connection.prepareStatement(sql1);
        statement2=connection.prepareStatement(sql2);
        ...
        //3. Execute the statements

        statement1.executeUpdate();
        statement2.executeUpdate();

        //4. Commit the changes

        connection.commit();
        }
    } catch (SQLException e ) {
        if (connection!=null) {
            try {
                connection.rollback();
            } catch(SQLException excep) {}
        }
    }finally {
        if (statement1 != null) {
            statement1.close();
        }
        if (statement2 != null) {
            statement2.close();
        }
       if(connection != null){
          connection.setAutoCommit(true);
          connection.close();
        }
   }

You have to prepare your Statement and create the batch after conn.setAutoCommit(false); .

When running this from a servlet, you have to make sure that the usage of the Connection is synchronized. Multiple requests could set the Connection to a different auto commit mode at nearly the same time. If you use one Connection per request, this will not be an issue. Otherwise, protect the above part with a critical section.

A tip regarding debugging which is applicable for tomcat / eclipse.

1) Enable JDPA debugging for your application server. In tomcat you can do this by adding the following lines to catalina.sh / catalina.bat:

 set JPDA_ADDRESS=8000
 set JPDA_TRANSPORT=dt_socket

2) Restart the application server

3) Connect with eclipse to your application server. "Debug as" --> "Remote Java Application"

4) Set a break point in above code.

5) Run the servlet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM