Java 多线程:Informix 12.10 - 无法执行物理顺序读取以获取下一行

Posted

技术标签:

【中文标题】Java 多线程:Informix 12.10 - 无法执行物理顺序读取以获取下一行【英文标题】:Java Multithreading: Informix 12.10 - Could not do a physical-order read to fetch next row 【发布时间】:2018-12-03 07:33:48 【问题描述】:

我们使用的是informix 12.10 版本。我们正在从 Java 批处理中删除 54 个表中的多行记录。我们在多线程中使用可调用策略。 请参考以下代码: SampleImpl.java:

Callable<Integer> callable=null;
List<Callable<Integer>> taskList = null;
List<Future<Integer>> futureList = null;
for (Map.Entry<String, String> entry : datas.entrySet())
    callable = new Callable<Integer>()
        public Integer call() throws Exception 
            return sampleDel.callSqlDelete();
        
    ;
    taskList.add(callable);

SampleDaoImpl:

public void callSqlDelete()
    Statement stmt = null;
    connection.setAutoCommit(false);
    stmt = connection.createStatement();
    stmt.execute("SET LOCK MODE TO WAIT");
    stmt.addBatch("DELETE FROM TABLE1 WHERE col1 IN(select from tableAAA where id=101)");
    stmt.addBatch("DELETE FROM TABLE2 WHERE col1 IN(select from tableAAA where id=101)"");
    int delCnt[] = stmt.executeBatch();
    connection.commit();

在我们的 java 代码中,我们已经将锁定模式设置为等待无限时间间隔,但我们仍然收到以下异常:

    java.sql.BatchUpdateException: Could not do a physical-order read to fetch next row.
        at com.informix.jdbc.IfxStatement.executeBatch(IfxStatement.java:1650)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at oracle.ucp.jdbc.proxy.StatementProxyFactory.invoke(StatementProxyFactory.java:272)
        at com.sun.proxy.$Proxy1.executeBatch(Unknown Source)
        at com.sample.samplereport.dao.impl.SampleDAOPurgeImpl.processDelByStmts(SampleDAOPurgeImpl.java:1305)
        at com.sample.samplereport.util.SamplePlSqlDeleter.callSqlDelete(SamplePlSqlDeleter.java:58)
        at com.sample.samplereport.dao.impl.SampleDAOPurgeImpl$1.call(SampleDAOPurgeImpl.java:298)
        at com.sample.samplereport.dao.impl.SampleDAOPurgeImpl$1.call(SampleDAOPurgeImpl.java:1)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
        at java.lang.Thread.run(Thread.java:662)

请帮忙解决上述问题?

【问题讨论】:

【参考方案1】:

对于这种类型的错误,查看 Informix 引擎也提供的 ISAM 错误代码通常会有所帮助。这提供了有关操作失败原因的更多信息,在这种情况下,为什么它无法读取下一行。获得 ISAM 错误的一种方法是在客户端 Java 环境中设置环境变量 APPENDISAM。可能还有其他方法可以实现这一目标。仅供参考,您可以在 https://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.jdbc_pg.doc/ids_jdbc_040.htm 的 Informix JDBC 驱动程序文档中找到更多信息

对于这个问题,我怀疑 ISAM 错误可能是 143“检测到死锁”。当一个线程需要等待另一个线程持有的锁时,就会出现这种情况,而另一个线程又在等待第一个线程已经持有的锁。由于您已将锁定模式设置为无超时等待,因此线程将永远等待,因此服务器会返回死锁错误。

为帮助避免该问题,您应该检查 TABLE1 和 TABLE2 是否优先使用行级锁定而不是页级锁定。您可能还想检查使用的隔离级别。如果使用可重复读取隔离或数据库为 ANSI 模式,则子查询中使用的 select 语句将在它考虑的每一行上放置一个锁,但如果“id”列上有索引,则应该最小化这些锁。

在应用程序代码级别,死锁通常通过回滚事务并重复执行来处理。

【讨论】:

来自服务器的 ISAM 错误通常附加为嵌套 SQLException。调用 getCause() 应该揭示潜在的问题,正如@simon-riddle 所指出的,这可能是一个死锁,因为多个线程删除正在尝试删除相同的行并且在彼此的锁上永远等待。

以上是关于Java 多线程:Informix 12.10 - 无法执行物理顺序读取以获取下一行的主要内容,如果未能解决你的问题,请参考以下文章

ubuntu12.10有多稳定啊?怎么觉得它反应很慢,而且会崩溃!

Informix 多连接

处理大量数字 C、Java、Informix

Informix java.lang.ClassNotFoundException: com.informix.jdbc.IfxDirectConnection

WARN - 获取ImportedKeys 失败游标先前已被释放且不可用

Informix:在 Java 中使用存储过程