数据从驱动程序JDBC转换到SAP HANA数据库时出错。

2020-08-24 09:07发布

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


美好的一天。

当前,我们有一个JAVA应用程序,可从数据库中通过驱动程序JDBC ngdbc-2.4.67.jar获取数据

SAP HANA 2.00.044.00.1571081837。 在大多数情况下,当应用程序正在读取数据并且将这些格式从二进制格式转换为字符串,int或十进制格式时,会出现错误,指示数组溢出。 下一个有关此问题的细节:

原因:java.lang.ArrayIndexOutOfBoundsException:7028547

com.sap.db.util.ByteUtils.getUByte(ByteUtils.java:38)〜[ngdbc-2.4 .67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7c4]

com.sap.db.jdbc.packet.HPart.getUByte(HPart.java:62)〜[ngdbc-2.4.67.jar! /:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7c4]

在com.sap.db.jdbc.packet.HDataPart._getFieldLengthFromDataLengthIndicator(HDataPart.java:1127)〜[ngdbc-2.4.67.jar!/:2.467。 -3028d4 \

615dae104ed3de580c64399b376bf8d7c4]
在com.sap.db.jdbc.packet.HDataPart._getFieldLength(HDataPart.java:1101)〜[ngdbc-2.4.67.jar!/:: 2.4.67-3028d4615dae104ed3de580c64399 \
b376bf8d7c4]
在com.sap.db.jdbc.packet.HDataPart._nextField(HDataPart.java:1033)〜[ngdbc-2.4.67.jar !/:2.4.67-3028d4615dae104ed3de580c64399b376b \

f8d7c4]

在com.sap.db.jdbc.packet.HDataPart.nextRecord(HDataPart.java:281)〜[ngdbc-2.4。 67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf \

8d7c4 ]

com.sap.db.jdbc.FetchChunk.nextRow(FetchChunk.java:111)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376b376bf8d7c4]

在com.sap.db.jdbc.ResultSetSapDB._next(ResultSetSapDB.java:4624)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8 \

d7c4]

> com.sap.db.jdbc.ResultSetSapDB.next(ResultSetSapDB.java:157)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7 \

c4]

有人可以帮助我解决这个问题吗?

问候。

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


美好的一天。

当前,我们有一个JAVA应用程序,可从数据库中通过驱动程序JDBC ngdbc-2.4.67.jar获取数据

SAP HANA 2.00.044.00.1571081837。 在大多数情况下,当应用程序正在读取数据并且将这些格式从二进制格式转换为字符串,int或十进制格式时,会出现错误,指示数组溢出。 下一个有关此问题的细节:

原因:java.lang.ArrayIndexOutOfBoundsException:7028547

com.sap.db.util.ByteUtils.getUByte(ByteUtils.java:38)〜[ngdbc-2.4 .67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7c4]

com.sap.db.jdbc.packet.HPart.getUByte(HPart.java:62)〜[ngdbc-2.4.67.jar! /:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7c4]

在com.sap.db.jdbc.packet.HDataPart._getFieldLengthFromDataLengthIndicator(HDataPart.java:1127)〜[ngdbc-2.4.67.jar!/:2.467。 -3028d4 \

615dae104ed3de580c64399b376bf8d7c4]
在com.sap.db.jdbc.packet.HDataPart._getFieldLength(HDataPart.java:1101)〜[ngdbc-2.4.67.jar!/:: 2.4.67-3028d4615dae104ed3de580c64399 \
b376bf8d7c4]
在com.sap.db.jdbc.packet.HDataPart._nextField(HDataPart.java:1033)〜[ngdbc-2.4.67.jar !/:2.4.67-3028d4615dae104ed3de580c64399b376b \

f8d7c4]

在com.sap.db.jdbc.packet.HDataPart.nextRecord(HDataPart.java:281)〜[ngdbc-2.4。 67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf \

8d7c4 ]

com.sap.db.jdbc.FetchChunk.nextRow(FetchChunk.java:111)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376b376bf8d7c4]

在com.sap.db.jdbc.ResultSetSapDB._next(ResultSetSapDB.java:4624)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8 \

d7c4]

> com.sap.db.jdbc.ResultSetSapDB.next(ResultSetSapDB.java:157)〜[ngdbc-2.4.67.jar!/:2.4.67-3028d4615dae104ed3de580c64399b376bf8d7 \

c4]

有人可以帮助我解决这个问题吗?

问候。

付费偷看设置
发送
10条回答
天桥码农
1楼-- · 2020-08-24 09:35

Lars美好的一天。

不幸的是,我无法设置有关该信息的详细信息,因此该信息是机密的。 但是,我可以共享一些有关代码的细节,特别是我使用的技术以及如何连接到数据库。 详细信息是:

1- Java 1.8

2- Spring Boot 1.5.16,Spring JDBC模板4.3.19

3-驱动程序JDBC ngdbc.2.4.67

应用程序获取数据库中存在的记录总数。 此后,应用程序计算将引发查询以获取所有信息的次数。 代码中最重要的部分是下一部分:

1-在应用程序中将信息从数据库映射到CustomObject的映射器。

公共CustomObject mapRow(ResultSet rs,int rowNum)抛出SQLException {CustomObject co = null;
    尝试{
 co = new CustomObject();
       idRecord = rs.getNString(" Field1");
       co.setField1(idRecord);
       co.setField2(rs.getNString(" Field2"));
       ...
       co.setField3(rs.getDouble(" Field3")); 
} catch(异常e){

       logger.error("错误[{}]。无法读取ID为[{}]的记录。",e,idRecord);

    }
    返回t
 } 

2-引发查询并获取信息的逻辑。

 @自动连线
 public void setJdbcTemplate(final JdbcTemplate jdbcTemplate){
     this.jdbcTemplate = jdbcTemplate;
 } 
 private int bloquesPorFetch = 4; 
公共静态最终字符串QUERY_SELECT =" SELECT ...."; 
公共DataPage Obtener(最终DataPage dp){
    尝试{
//要查询的参数。
       List  parametrosTemp =(List )dp.getParametros()。get(" params");

      //要在每个查询中获取的记录总数。
       parametrosTemp.add(dp.getPageSize());

      //要在查询中偏移的值。
       parametrosTemp.add(((dp.getPage()-1)* dp.getPageSize()); 
 
//pageSize =一百万条记录,此记录设置在应用程序的另一层中。
       jdbcTemplate.setFetchSize(dp.getPageSize()/bloquesPorFetch);
       List 记录= jdbcTemplate.query(
 QUERY_SELECT,parametrosTemp.toArray(),新的CustomObjectMapper());

       logger.info("正在获取[{}]条记录。",records.size());

       DataPage dpTemp =新的DataPage();
       dpTemp.setTotalRegistros(dp.getTotalRegistros());
       dpTemp.setPageSize(dp.getPageSize());
       dpTemp.setTotalPaginas(dp.getTotalPaginas());
       dpTemp.setResultado(records);

       返回dpTemp; 
} catch(DataAccessException e){
//包装原始异常原因并提供业务消息。
       抛出新的ServicioNoDisponibleException("数据库不可用。",e);
    } catch(异常e){
//包装原始异常原因并提供业务消息。
       抛出新的ServicioNoDisponibleException("无法处理该请求。",e);

    }

 } 

另一方面,我实现了一些测试,以尝试找出导致问题的记录块。 但是,信息化似乎不是问题。 实现的活动是:

-首先,我加载了大约一百万条记录,但我找不到错误。

-第二,我再加载一百万,我的意思是,加载了两百万条记录,我可以得到此错误。 此外,我还确定了可能导致问题的数据块。

-第三,我删除了所有信息,并刚刚加载了似乎引起问题的数据块

-最后,我再次执行了测试,但是我没有解决问题。

据此,我认为数据不是问题。

您能提供一些建议以尝试解决问题吗?

致谢。

追夢秋陽
2楼-- · 2020-08-24 09:23

您可以添加代码和数据来重现此问题吗? 基于堆栈回溯,我的猜测是网络级别的数据有损坏。

槿木_熙
3楼-- · 2020-08-24 09:37

对我来说,问题似乎并不直接取决于您从数据库请求的实际数据。 如果是这样,那么您应该能够使用一部分数据重现该问题,并且该问题不起作用。

因此,我能想到的下一件事是, 您的应用程序与数据库之间的通信。 毕竟,调用堆栈指示JDBC驱动程序的低级网络字节流解码中的数组索引溢出。

退后一步,从代码中脱颖而出的是非常不寻常的方法 对数据进行分块。 我不确定这的目的是什么,但现在让我们将其放在一边。

使用.setFetchSize(),您可以设置每个网络请求的最大记录数(这不是往返,而是 结果集记录可以跨越许多网络数据包,这些数据包将导致JDBC驱动程序尝试从数据库获取ACK响应。 这里的想法是,客户端应用程序需要能够接收fetch()调用的整个响应,即它需要用于此操作的内存,并且使用.setFetchSize()可以指示有足够的​​内存来存储X条记录 。

如果数据库是您的水井,则fetchSize不是您的水桶大小,而是您想要填充的意大利面锅的大小(但这不是您需要的全部水) 还是要整顿饭,然后想想汤和菜肴:))。

到目前为止很好。 通常,fetchSize()并不是很复杂。 开发人员会考虑可能有多少内存,并可能为其配置一个参数来为整个应用程序服务。

您的代码做什么,但是通过更改每个jdbcTemplate的值似乎有点过分渴望- 是一个弹簧构造; 我不知道最终如何将其映射到JDBC对象。

无论如何,我的印象是JDBC驱动程序与fetchSizes的更改混为一谈,最终不得不处理字节流 没有预期大小的数组(包含对fetch()调用的响应的数组)。

看看其余的代码,我得到的印象是您想要实现一些自卷式分页 ,其中两个查询参数是blocksize和要返回的块的max-record。

显然,此方法要求查询或要查询的视图内置这些参数。

我认为这不是实现您要完成的工作的很好方法。
首先,fetchSize与结果集分页无关,而仅与客户端和数据库之间的网络通信有关。
然后,首先在单独的事务中对记录进行计数,然后根据 结果意味着要处理过时的数据,因为记录数可能会同时更改(您没有锁定表,对吗?)。
具有不同参数的重复查询也是如此-这些查询是 不保证使用相同的数据集,因为表中的数据可能已更改。 记录10可能会变成介于两者之间的记录10000010,并在您的应用程序的总体结果集中出现两次。

我将不介绍如何处理此问题,因为这导致与原始问题相去甚远,但是 对于网络问题,我的建议是:不要一遍又一遍地更改fetchSize()(也许Spring会重用连接/声明对象实例-我不知道)。 在您的应用程序中设置一次(如果您需要),然后将其保留。

然后,考虑setMaxrows()是否不是您想要实现的最佳选择。 再次,不要过度采用一些聪明的动态方法来计算此上限,只需将其设置为一个合理的值,然后看是否对您的应用程序有效。

如果您想沿着 要修复JDBC驱动程序中的错误,建议打开SAP支持事件。 但是,如果问题源于Spring如何使用JDBC对象以及某些未指定的行为(例如,哪些对象必须或应该是线程安全的),我不会感到惊讶。

N-Moskvin
4楼-- · 2020-08-24 09:14

很好 。 给定没有setFetchSize的测试结果,可能会导致问题的发生而将其排除在外。

我的下一步是运行网络连接测试。 例如。 使用iperf3并查看系统与HANA服务器之间的网络连接是否稳定并且没有传送乱码的数据。

另一件事:越界索引(7028547)始终相同还是发生变化? ?

Alawn_Xu
5楼-- · 2020-08-24 09:26

非常感谢您的答复。

为了弄清楚一些事情,有效地,我实现了一种机制来分页数百万条记录并避免消耗大量JVM的内存。 到目前为止,我对参数没有任何疑问,可以在所请求的每个页面中获取信息。 为了控制这一点,我在查询中使用了参数" limit"和" offset"。

另一方面,我意识到测试改变了应用程序如何连接数据库的实现,我的意思是,我仅使用API​​ Java JDBC(不使用Spring JDBC模板),结果却完全相同(由以下原因引起: java.lang.ArrayIndexOutOfBoundsException:7028547)。 此外,通过使用Spring JDBC模板的实现,我实现了一个测试,而没有指定获取值,换句话说,使用默认值,但是我遇到了同样的问题。

最后,我想提到这个问题已经报告过,但是直到现在还没有解决。

预先,谢谢您的建议。

致谢。

太Q了
6楼-- · 2020-08-24 09:23

根据我的经验,支持同事在收集数据以进行故障排除方面非常周到。 如果我是JDBC开发人员,则肯定要查看该跟踪。 错误不在其中的事实并不意味着跟踪文件没有用。

我猜想跟踪器不会捕获ArrayOutOfIndexBounds异常,但是事先发生的事情应该是 覆盖。

再次确认一下:7028547是您通过setFetchSize()设置的数字,还是无论您进行任何设置而都会出现的数字?

一周热门 更多>