背景描述:
项目中,客户的工厂有一台检测产品指标的检测仪,其检测结果存储在本地电脑的Access数据库中。项目的目的是服务器连接这台电脑,通过rmi的方式进行连接,读取这台电脑上的Access数据库的mdb文件中的内容。
Java 在服务器上通过RMI的方式访问客户电脑上的Access数据库中的内容的方法可以参考:https://blog.csdn.net/hongdi/article/details/5482470 中的介绍,很详细了。
错误描述:
在读取客户电脑上的Access数据库中的数据时,最开始一切都很正常,从某一时间点开始,报如下错误:
1 java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 无效的字符串或缓冲区长度 2 at sun.jdbc.odbc.JdbcOdbc.createSQLException(Unknown Source) 3 at sun.jdbc.odbc.JdbcOdbc.standardError(Unknown Source) 4 at sun.jdbc.odbc.JdbcOdbc.SQLGetDataString(Unknown Source) 5 at sun.jdbc.odbc.JdbcOdbcResultSet.getDataString(Unknown Source) 6 at sun.jdbc.odbc.JdbcOdbcResultSet.getString(Unknown Source) 7 at org.objectweb.rmijdbc.RJResultSetServer.getString(RJResultSetServer.java:144) 8 at sun.reflect.GeneratedMethodAccessor59.invoke(Unknown Source) 9 at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 10 at java.lang.reflect.Method.invoke(Unknown Source) 11 at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) 12 at sun.rmi.transport.Transport$2.run(Unknown Source) 13 at sun.rmi.transport.Transport$2.run(Unknown Source) 14 at java.security.AccessController.doPrivileged(Native Method) 15 at sun.rmi.transport.Transport.serviceCall(Unknown Source) 16 at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) 17 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) 18 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(Unknown Source) 19 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source) 20 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source) 21 at java.security.AccessController.doPrivileged(Native Method) 22 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) 23 at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 24 at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 25 at java.lang.Thread.run(Unknown Source) 26 at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:283) 27 at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:260) 28 at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161) 29 at org.objectweb.rmijdbc.RJResultSetServer_Stub.getString(Unknown Source) 30 at org.objectweb.rmijdbc.RJResultSet.getString(RJResultSet.java:143)
经查,用户的电脑的操作系统为64位Windows 7系统。同样的代码,当用户的电脑是32位Windows XP时就好用,不报错。
程序中读取数据的代码如下:
1 String sampNo = rs.getString(1);
经过不断的查找,终于在这篇帖子上找到了问题的根源:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8038751
是因为Jdk 1.6/7在64位操作系统上JDBC-ODBC桥上的Bug,导致在调用ResultSet.getObject()/getString()的时候随机并且不定时的报出 [Microsoft][ODBC 驱动程序管理器] 无效的字符串或缓冲区长度 这个错误。并不是一定会报错,可能是正常的运行了一段时间之后才报出来。
这也解释了为什么当用户电脑是Windows XP时读取没问题,当用户是Windows 7 64位的时候才会有问题。
解决方法: 避免使用ResultSet.getObject()/getString(),根据数据库的类型,如果是数字使用getLong,如果是字符串使用getBytes来进行读取。比如:
1 String remark = new String(rs.getBytes(4), "gbk");
至此,此问题再也没有再复现过,问题解决!