我正在使用与Firebird的JDBC连接。

<groupId>org.firebirdsql.jdbc</groupId>
<artifactId>jaybird-jdk18</artifactId>
<version>3.0.5</version>


当我通过以下方式读取数据时:

resultSet.next(); //resultSet is instance of FBResultSet


有时线程会在这里阻塞:

 private native int socketRead0(FileDescriptor fd,
                                   byte b[], int off, int len,
                                   int timeout)
        throws IOException;


而且线程永远不会继续。我需要重新启动整个应用程序。 :(

如何解决此问题?我从这里尝试了一些参数:
https://dzone.com/articles/threads-stuck-in-javanetsocketinputstreamsocketrea

-Dsun.net.client.defaultConnectTimeout=10000
-Dsun.net.client.defaultReadTimeout=10000


但没有积极的结果。我什至不知道超时值是多少。我不能在那个地方调试它。 (java.net.SocketInputStream)

与数据库的连接已连接到云服务器,我认为这就是问题所在。

是否有可能以某种方式解决此问题?还是将超时设置为firebird jdbc?

感谢您的回答。

编辑:
这是线程阻塞的屏幕:
java - Jaybird SocketInputStream.socketread0线程阻塞-LMLPHP

最佳答案

在您的情况下,根本原因是在firebird.conf中启用有线加密(设置WireCrypt = Enabled)时,Jaybird 3.0.4至3.0.7(和4.0.0-beta-1)中的Firebird 3(和4)中存在错误。 。

我以前只在Jaybird 4的测试按特定顺序运行时才看到Jaybird 4的问题,并且由于该版本尚未发布,因此我没有优先考虑查找根本原因。

在您的帮助下(再次感谢!),我能够确定问题所在。现在,此错误已在Jaybird 3.0.8中修复,可从Firebird: JDBC Driver获得。

错误说明

Firebird有线协议中的某些类型的缓冲区(例如,列数据)以字节填充为四的倍数。 Jaybird中的实现依靠InputStream.skip(long)跳过此填充。

具体来说,它做到了:

public int skipFully(int n) throws IOException {
    int total = 0;
    int cur;
    while (total < n && (cur = (int) in.skip(n - total)) > 0) {
        total += cur;
    }
    return total;
}


这在没有有线加密的情况下效果很好,因为除非关闭套接字,否则skipBufferedInputStreamSocketInputStream实现的组合对于每次对skip的调用至少会跳过1个字节。

添加CipherInputStream时,这种期望不再成立:如果BufferedInputStream的缓冲区中没有字节,它将在skip(long)上调用CipherInputStream,如果在其缓冲区的末尾,它将跳过0个字节(skip允许)。

结果,Jaybird可能会跳过太少的1个,2个或3个字节,这导致后续的读取操作读取了错误的数据。最终,这将导致错误地读取缓冲区大小,导致读取阻塞以等待更多数据,或者将导致Jaybird读取错误的操作代码,这将导致异常,并以“不支持或意外操作开头”消息码”。

行为类似的其他问题的解决方法或解决方案

作为挂起连接的一种解决方法,可以使用连接属性soTimeout设置套接字读取超时(请参见Jaybird Manual, appendix A.2 Other properties)。

问题还可能是Firebird在锁上无限期地“只是”等待。要排除Firebird等待锁定,您还可以更改事务等待模式或超时。 Jaybird的默认设置是使用无限期等待。

例如,要将读取提交的等待模式更改为不等待,可以将连接属性TRANSACTION_READ_COMMITTED设置为值read_committed,rec_version,write,nowait

要使用等待但有超时的情况,可以使用值read_committed,rec_version,write,wait,lock_timeout=5。这将应用5秒钟的锁定超时。

如果您的问题是由于Firebird等待另一个事务持有的锁而引起的,则这将导致异常,其中包含在无等待事务(对于nowait选项)上的锁冲突或在等待事务上的锁超时(为lock_timeout选项)。

另请参见Jaybird Manual, appendix A.3 Transaction isolation levelsJaybird Manual, section 6.4. Transaction Isolation Levels(尽管现在我需要在其中添加更多信息)。

09-28 09:32