我正在调用一种方法,它对 DB2 数据库中的单个数据集执行 SQL UPDATE。从 ActiveMQ 队列接收到消息后,该方法在不同的线程中自动调用。它在 2 秒内被调用了 5 次,但是因为第一次调用在数据集上设置了 WRITE-Lock,所以接下来的 3 次调用必须等待。在第一次调用完成更新后,第二次调用不会执行更新,而是会运行一个新的方法调用(行中的第 5 个调用)。问题是,中间的三个调用没有识别出 WRITE-Lock 被释放,并且在 1 分钟超时后抛出了一个 SQLException 错误 SQL0913。
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
该数据库是 IBM DB2 数据库(7.2 版),我的程序在 JBoss EAP-6.4 上运行。从日志来看,第一个调用似乎需要几秒钟才能执行,在接下来的三个调用之间正在等待第一个调用。但是在第一个完成执行后,接下来的三个调用没有进行。
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();
}
我希望,在第一次调用完成后,接下来的三个 SQL 更新调用将按调用顺序执行。