Error Handling

There are methods to check for, identify, and handle errors in a TimesTen Java application.

For a list of the errors that TimesTen returns and what to do if errors are encountered, see Errors and Warnings in Oracle TimesTen In-Memory Database Error Messages and SNMP Traps.

This section includes the following topics.

Error and Warning Levels

When operations are not completely successful, TimesTen can return a fatal error, a non-fatal error, or a warning.

The sections that follow discuss error or warning situations and how to handle them:

Fatal Errors

Fatal errors make the database inaccessible until it can be recovered. When a fatal error occurs, all database connections are required to disconnect. No further operations may complete.

Fatal errors are indicated by TimesTen error codes 846 and 994. Error handling for these errors should be different from standard error handling. In particular, the code should roll back the current transaction and, to avoid out-of-memory conditions in the server, disconnect from the database. Shared memory from the old TimesTen instance is not freed until all connections that were active at the time of the error have disconnected. Inactive applications still connected to the old TimesTen instance may have to be manually terminated.

When fatal errors occur, TimesTen performs the full cleanup and recovery procedure:

  • Every connection to the database is invalidated, a new memory segment is allocated and applications are required to disconnect.

  • The database is recovered from the checkpoint and transaction log files upon the first subsequent initial connection.

    • The recovered database reflects the state of all durably committed transactions and possibly some transactions that were committed non-durably.

    • No uncommitted or rolled back transactions are reflected.

Non-Fatal Errors

Non-fatal errors include errors such as an INSERT statement that violates unique constraints. This category also includes some classes of application and process failures.

TimesTen returns non-fatal errors through the typical error-handling process. Application should check for errors and appropriately handle them.

When a database is affected by a non-fatal error, an error may be returned and the application should take appropriate action.

An application can handle non-fatal errors by modifying its actions or, in some cases, by rolling back one or more offending transactions, as described in Rolling Back Failed Transactions.

Also see Reporting Errors and Warnings, which follows shortly.

Note:

If a ResultSet, Statement, PreparedStatement, CallableStatement or Connection operation results in a database error, it is a good practice to call the close() method for that object.

Warnings

TimesTen returns a warning when something occurs that is unexpected but not considered very serious.

Here are some examples of events that cause TimesTen to issue a warning:

  • A checkpoint failure

  • Use of a deprecated TimesTen feature

  • Truncation of some data

  • Execution of a recovery process upon connect

  • Replication return receipt timeout

You should always have code that checks for warnings, as they can indicate application problems.

Also see Reporting Errors and Warnings immediately below.

Abnormal Termination

In some cases, such as with a process failure, an error cannot be returned, so TimesTen automatically rolls back the transactions of the failed process.

Reporting Errors and Warnings

Your application should check for and report all errors and warnings that can be returned on every call. This saves considerable time and effort during development and debugging.

A SQLException object is generated if there are one or more database access errors and a SQLWarning object is generated if there are one or more warning messages. A single call may return multiple errors or warnings or both, so your application should report all errors or warnings in the returned SQLException or SQLWarning objects.

Multiple errors or warnings are returned in linked chains of SQLException or SQLWarning objects. The examples below demonstrate how you might iterate through the lists of returned SQLException and SQLWarning objects to report all of the errors and warnings, respectively.

The following method prints out the content of all exceptions in the linked SQLException objects.

static int reportSQLExceptions(SQLException ex)
  {
    int errCount = 0;
    if (ex != null) {
      errStream.println("\n--- SQLException caught ---");
      ex.printStackTrace();

      while (ex != null) {
        errStream.println("SQL State: " + ex.getSQLState());
        errStream.println("Message: " + ex.getMessage());
        errStream.println("Error Code: " + ex.getErrorCode());
        errCount ++;
        ex = ex.getNextException();
        errStream.println();
      }
    }

    return errCount;
}

This next method prints out the content of all warning in the linked SQLWarning objects.

static int reportSQLWarnings(SQLWarning wn)
{
    int warnCount = 0;

    while (wn != null) {
      errStream.println("\n--- SQL Warning ---");
      errStream.println("SQL State: " + wn.getSQLState());
      errStream.println("Message: " + wn.getMessage());
      errStream.println("Error Code: " + wn.getErrorCode());

      // is this a SQLWarning object or a DataTruncation object?
      if (wn instanceof DataTruncation) {
        DataTruncation trn = (DataTruncation) wn;
        errStream.println("Truncation error in column: " +
          trn.getIndex());
      }
      warnCount++;
      wn = wn.getNextWarning();
      errStream.println();
    }
    return warnCount;
}

Catching and Responding to Specific Errors

In some situations it may be desirable for your application to respond in a certain way to a specific SQL state or TimesTen error code. You can use the SQLException method getSQLState() to return the SQL state and the getErrorCode() method to return TimesTen error codes.

Also refer to the entry for TimesTenVendorCode in Oracle TimesTen In-Memory Database JDBC Extensions Java API Reference.

The TimesTen Classic s Quick Start ample applications require you to load the schema before executing the samples. The following catch statement alerts the user that appuser has not been loaded or has not been refreshed by detecting ODBC error S0002 and TimesTen error 907:

catch (SQLException ex) {
  if (ex.getSQLState().equalsIgnoreCase("S0002")) {
    errStream.println("\nError: The table appuser.customer " +
      "does not exist.\n\t Please reinitialize the database.");
  } else if (ex.getErrorCode() == 907) {
    errStream.println("\nError: Attempting to insert a row " +
      "with a duplicate primary key.\n\tPlease reinitialize the database.");
}

You can use the TimesTenVendorCode interface to detect the errors by their name, rather than their number.

Consider this example:

ex.getErrorCode() == com.timesten.jdbc.TimesTenVendorCode.TT_ERR_KEYEXISTS

The following is equivalent:

ex.getErrorCode() == 907

Rolling Back Failed Transactions

In some situations, such as recovering from a deadlock or lock timeout, you should explicitly roll back the transaction using the Connection method rollback().

try {
  if (conn != null && !conn.isClosed()) {
    // Rollback any transactions in case of errors
      if (retcode != 0) {
        try {
          System.out.println("\nEncountered error. Rolling back transaction");
          conn.rollback();
        } catch (SQLException ex) {
          reportSQLExceptions(ex);
        }
      }
   }

    System.out.println("\nClosing the connection\n");
    conn.close();
} catch (SQLException ex) {

  reportSQLExceptions(ex);
}

A transaction rollback consumes resources and the entire transaction is in effect wasted. To avoid unnecessary rollbacks, design your application to avoid contention and check the application or input data for potential errors before submitting it.

Note:

If your application terminates, crashes, or disconnects in the middle of an active transaction, TimesTen automatically rolls back the transaction.

Retrying After Transient Errors (JDBC)

TimesTen automatically resolves most transient errors (which is particularly important for TimesTen Scaleout), but if your application detects the following SQLSTATE value, it is suggested to retry the current transaction.

  • TT005: Transient transaction failure due to unavailability of resource. Roll back the transaction and try it again.

Note:

Search the entire error stack for errors returning these error types before deciding whether it is appropriate to retry.

This is returned by the getSQLState() method of the SQLException class and may be encountered by method calls from any of the following JDBC types:

  • Connection

  • Statement

  • PreparedStatement

  • CallableStatement

  • ResultSet

  • Connection

  • Statement

  • PreparedStatement

  • CallableStatement

  • ResultSet

Here is an example:

// Database connection object
Connection        dbConn;
 
// Open the connection  to the database
...
 
// Disable auto-commit
dbConn.setAutoCommit( false ); 
 
...
 
// Prepre the SQL statements
PreparedStatement stmtQuery = dbConn.prepare("SELECT ...");
PreparedStatement stmtUpdate = dbConn.prepare("UPDATE ...");
 
...
 
// Set max retries for transaction to 5
int retriesLeft = 5;
 
// Records outcome
boolean success = false;
 
// Excute transaction with retries until success or retries exhausted
while (  retriesLeft > 0  )
{
    try {
 
        // First execute the query
 
        // Set input values
        stmtQuery.setInt(1, ...);
        stmtQuery.setString(2, ...);
 
        // Execute and process results
        ResultSet rs = stmtQuery.executeQuery();
        while (  rs.next()  )
        {
            int val1 = rs.getInt(1);
            String val2 = rs.getString(2);
            ...
        }
        rs.close();
        rs = null;
          
        // Now excute the update
 
        // Set input values
        stmtUpdate.setInt(1,...);
        stmtUpdate.setString(2,...);
 
        // Execute and check number of rows affected
        int updCount = stmtUpdate.executeUpdate();
        if (  updCount < 1  )
        {
            ...
        }
 
        // And finally commit
        dbConn.commit();
 
        // We are done
        success = true;
        break;
 
    } catch ( SQLException sqe ) {
 
        if (  sqe.getSQLState().equals("TT005")  ) // grid transient error
        {
            // decrement retry count
            retriesLeft--;
            // and rollback the transaction ready for retry
            try {
                dbConn.rollback();
            } catch ( SQLException sqer ) {
                // This is a fatal error so handle accordingly
            }
        }
        else
        {
            // handle other kinds of error
            ...
        }
    }
} // end of retry loop
 
if (  ! success  )
{
    // Handle the failure
    ...
}

Note:

The example in Failover Delay and Retry Settings also shows how to retry for transient errors.