Search code examples
javadb2db2-400jboss-eap-6jpa

How to fix 'SQLException SQL0913' after calling SQL update in different threads


I'm calling a method, that does an SQL UPDATE on a single dataset in a DB2 database. The method is called automatically in different threads after receiving message from an ActiveMQ queue. It is called 5 times in 2 seconds, but because the first call sets a WRITE-Lock on the dataset, the next 3 calls have to wait. After the first call finishes the update, the second call is not executing the update, instead, a new method call (the 5th call in the row) runs through. The Problem is, that the three calls in between are not recognizing, that the WRITE-Lock was released, and are throwing a SQLException with error SQL0913 after a timeout of 1 minute.

Caused by: java.sql.SQLException: [SQL0913] Zeile oder Objekt PR1BAFPU5 der Art *FILE in DAKDTA wird verwendet. Ursache  . . . . :  Das angeforderte Objekt PR1BAFPU5 der Art *FILE in der Bibliothek DAKDTA wird gerade von einem anderen Anwendungsprozess verwendet, oder eine Zeile im Objekt wird von einem anderen Anwendungsprozess oder einem anderen Cursor in diesem Anwendungsprozess verwendet. Fehlerbeseitigung:  Die vorherigen Nachrichten im Jobprotokoll aufrufen (Befehl DSPJOBLOG) oder im interaktiven SQL F10 (Nachrichten im Jobprotokoll anzeigen) in dieser Anzeige drücken, um zu bestimmen, ob es sich um eine Wartezeitüberschreitung für eine Objekt- oder Satzsperre handelt. Einen der folgenden Schritte durchführen: -- Wird ein Objekt durch einen anderen Anwendungsprozess gesperrt, die SQL-Anweisung wiederholen, wenn das Objekt nicht verwendet wird. Mit dem Befehl WRKOBJLCK (Mit Objektsperren arbeiten) kann festgestellt werden, von wem das Objekt gerade verwendet wird. -- Ist das Objekt ein Schema und wurde versucht, in diesem Schema eine Tabelle, eine Sicht oder einen Index unter COMMIT-Steuerung zu erstellen, wird möglicherweise für dieses Schema gerade eine Operation zum "Sichern im aktiven Zustand" von einem anderen Job im System durchgeführt. Ist die Operation zum "Sichern im aktiven Zustand" abgeschlossen, die Anforderung wiederholen. -- Wird ein Satz durch einen anderen Anwendungsprozess gesperrt, die SQL-Anweisung wiederholen, wenn der Satz nicht verwendet wird. Mit dem Befehl DSPRCDLCK (Satzsperren anzeigen)kann festgestellt werden, von wem der Satz gerade verwendet wird. -- Wird der Satz von einem anderen Cursor in demselben Anwendungsprozess gesperrt, muss eine Anweisung COMMIT, ROLLBACK oder eine andere Anweisung FETCH für den Cursor ausgegeben werden, der die Sperre verursacht, bevor diese SQL-Anweisung ausgegeben wird. Tritt dieser Fehler häufig auf, mit dem Befehl CHGPF (Physische Datei ändern), CHGLF (Logische Datei ändern) oder OVRDBF (Datenbankdatei überschreiben) die Wartezeitüberschreitung für das Objekt oder den Satz ändern. 
        at com.ibm.as400.access.JDError.createSQLExceptionSubClass(JDError.java:860) [jt400-jdbc4-7.8.jar:JTOpen 7.8] 
        at com.ibm.as400.access.JDError.throwSQLException(JDError.java:692) [jt400-jdbc4-7.8.jar:JTOpen 7.8] 
        at com.ibm.as400.access.JDError.throwSQLException(JDError.java:662) [jt400-jdbc4-7.8.jar:JTOpen 7.8] 
        at com.ibm.as400.access.AS400JDBCStatement.commonExecute(AS400JDBCStatement.java:1025) [jt400-jdbc4-7.8.jar:JTOpen 7.8] 
        at com.ibm.as400.access.AS400JDBCPreparedStatement.executeUpdate(AS400JDBCPreparedStatement.java:1649) [jt400-jdbc4-7.8.jar:JTOpen 7.8] 
        at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:493) 
        at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:186) [hibernate-core-4.2.27.Final-redhat-1.jar:4.2.27.Final-redhat-1] 
        ... 143 more 

The database is a IBM DB2 database (version 7.2), and my program is running on a JBoss EAP-6.4. From the logs, it looks like that the first call takes several seconds to execute, in between the next three calls are waiting for the first one. But after the first one finished execution, the next three calls are not proceeding.

public void updateBerthTimeConflictFlag4BerthArrival(boolean conflict, String berthArrivalId) { 
                Query updateQuery = em.createNativeQuery("update PR1BERTHARRIVAL_FLZ set berthTimeConflict = :conflict where id = :id"); 
                updateQuery.setParameter("conflict", conflict ? 1 : 0); 
                updateQuery.setParameter("id", berthArrivalId); 
                updateQuery.executeUpdate(); 
        } 

I would expect, that after the first call finishes, the next three calls of the SQL update are executed in the order of the call.


Solution

  • We had the same problem times ago, and we follow this:

    Problem(Abstract)

    When an application reads a number of records using JDBC from a table and uses a BMP entity bean to delete the records from the table, the error "java.sql.SQLException: [SQL0913] Row or object F55500 in type *FILE in use" occurs.

    Cause

    The exception indicates that the rows or objects are in use.

    Resolving the problem

    In the JDBC program that reads a number of records, you need to ensure that all connections are closed so that all resources are released. If there is no direct way for releasing the connection, restarting the database would remove any open connections but this would be a last measure if there is no other alternative for release the connections. Instead of using a JDBC program, create a separate session bean to contain the query to the database. The session bean should have a transaction setting of RequiresNew. The SQL statement now runs in a new separate transaction. Once the method has completed running, the transaction is ended and the tables are freed to be used by the BMP entity beans to delete.

    Here the original technote