使用c3p0 0.9.2.1、hibernate 4.2.21、JBoss AS 7.1.1并连接Microsoft SQL Server 2014-12.0.2000.8(X64)。
mssqljdbc6.2.2(我测试了6.4.0,但我们使用的是6.2.2)用于JRE7支持。
场景
以多行形式从表中检索数据,但不能同时检索。这只是一个循环,每次检索一行并最终放入HashMap。
问题&输出
经过长时间的调查和调试,我发现问题范围与表中的两列有关。一个是称为VARBINARY(MAX)的签名,另一个是名为VARCHAR(1024)的状态。如果这两列在一行上都有值,则在检索下一行时会发生此异常。如果其中任何一个被设置为null,那么一切都是好的。不管它们中的值有多长。
迄今为止的尝试
- 更改列的顺序使VARCHARcolumn成为最后一个障碍
- 更改列的顺序使VARBINARY列成为最后一个秋天
- 更改长度(VARBINARY为8000,VARCHAR为50)
- 在长度相似或较大的其他列上设置值
- 记录
org.hibernate.session
对象方法isConnected()
和isOpen()
,并且在抛出异常之前,两者的输出始终为true
问题
这个例外是什么意思?特别是sql server日志记录没有显示任何关于它的信息!!
为什么会发生这种情况,原因可能是什么?
18:53:12,294 SEVERE [com.microsoft.sqlserver.jdbc.internals.TDS.TOKEN]
(http-localhost-127.0.0.1-8080-6) ConnectionID:24 ClientConnectionId:
5bbf35a7-2a3c-4fb5-845a-bbd81d2739ef: getNextResult: Encountered
unexpected unknown token (0x1)
18:53:12,296 SEVERE [com.microsoft.sqlserver.jdbc.internals.TDS.Reader]
(http-localhost-127.0.0.1-8080-6) ConnectionID:24 ClientConnectionId:
5bbf35a7-2a3c-4fb5-845a-bbd81d2739ef got unexpected value in TDS
response at offset:1158
18:53:12,300 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) java.lang.reflect.InvocationTargetException
18:53:12,300 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
18:53:12,301 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
18:53:12,301 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
18:53:12,302 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at java.lang.reflect.Method.invoke(Unknown Source)
.
.
18:53:12,304 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
18:53:12,305 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
18:53:12,306 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
18:53:12,307 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
18:53:12,308 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
18:53:12,309 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
18:53:12,309 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329)
18:53:12,310 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
.
.
18:53:12,312 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
18:53:12,312 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
.
.
18:53:12,314 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
18:53:12,314 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
.
.
18:53:12,316 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
18:53:12,316 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
18:53:12,317 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:101)
18:53:12,318 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280)
18:53:12,318 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248)
18:53:12,319 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
18:53:12,320 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
18:53:12,320 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153)
18:53:12,321 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
18:53:12,322 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
18:53:12,322 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
18:53:12,323 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368)
18:53:12,324 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
18:53:12,325 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671)
18:53:12,326 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930)
18:53:12,327 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at java.lang.Thread.run(Unknown Source)
18:53:12,328 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) Caused by: org.hibernate.exception.GenericJDBCException: could not
extract ResultSet
18:53:12,329 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
18:53:12,330 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:124)
18:53:12,332 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
18:53:12,333 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:88)
18:53:12,335 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.getResultSet(Loader.java:2062)
18:53:12,336 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1859)
18:53:12,337 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1838)
18:53:12,338 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.doQuery(Loader.java:906)
18:53:12,339 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:348)
18:53:12,340 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.doList(Loader.java:2550)
18:53:12,340 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.doList(Loader.java:2536)
18:53:12,341 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2366)
18:53:12,342 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.Loader.list(Loader.java:2361)
18:53:12,342 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495)
18:53:12,343 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:357)
18:53:12,343 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:198)
18:53:12,344 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1230)
18:53:12,345 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
18:53:12,345 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.internal.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:909)
.
.
18:53:12,350 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) ... 38 more
18:53:12,351 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The
connection is closed.
18:53:12,351 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:228)
18:53:12,352 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.microsoft.sqlserver.jdbc.SQLServerConnection.checkClosed(SQLServerConnection.java:1007)
18:53:12,353 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.microsoft.sqlserver.jdbc.SQLServerStatement.checkClosed(SQLServerStatement.java:1024)
18:53:12,353 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:198)
18:53:12,354 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:401)
18:53:12,355 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:116)
18:53:12,355 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
18:53:12,356 ERROR [stderr] (http-localhost-127.0.0.1-8080-6) ... 59 more
以下解决了检索问题,并显示在一些提交行中(插入和刷新)。从数据库向驱动程序检索数据似乎太多了,因为VARBINARY在Java中映射到LOB,并且作为大型对象打开的流不会很快关闭,直到另一个检索到达数据库和驱动程序,这导致了这个问题。这是的解决方案
如果使用cursorJDBC属性检索数据,那么问题就迎刃而解了。当github上的Microsoft团队清除了直接从JDBC驱动程序抛出的异常,并提供了一个正在运行的示例代码时,我(直到现在)未能复制该问题。
使用游标只是将selectMethod=cursor
添加到JDBC url中。要完全了解此选项的作用以及它如何影响数据检索,特别是LOB类型,请参阅本文档和本文。
来自Microsoft文档
selectMethod,String,["direct"|"cursor"],默认为
direct
如果此属性设置为"游标",则会为创建数据库游标在TYPE_FORWARD_ONLY的连接上创建的每个查询,以及CONCUR_READ_ONLY游标。通常只有在以下情况下才需要此属性应用程序生成的大型结果集不能完全包含在客户端内存中。当此属性设置为"cursor"时客户端中只保留有限数量的结果集行记忆力
默认行为是所有结果集行都保留在客户端内存。当应用程序正在处理所有行。
来自问答文章
需要考虑的一些问题:
- 应用程序是否使用可滚动的结果集、仅转发的结果集或两者兼而有之?如果是可滚动的,它们会获取所有数据还是只滚动到并提取一些行
- 生成的结果集是小的还是大的?这包括行和列的数量以及中包含的数据(即是否有LOB)
- 应用程序是执行事务性工作还是仅在自动提交模式下运行
- 应用程序是否在单个连接上一次打开多个结果集
这些问题的答案应该有助于决定哪种连接参数最适合应用程序。首先要注意完全从连接URL中删除该选项是与将选项设置为"直接"相同,因为"直接"是默认值背景
接下来,我们来看看JDBC中对此选项的描述用户指南和参考手册。以下是此描述:
对驱动程序的提示,用于确定驱动程序是否请求Select语句的数据库游标。的性能和行为驱动程序受此属性的影响,该属性被定义为提示因为驾驶员可能并不总是能够满足要求方法
如果设置为direct(默认值),则数据库服务器发送完整的在对查询如果请求结果集类型是仅向前的结果集。通常,响应是驱动程序未缓存。使用此方法,驱动程序必须处理提交另一个查询之前对查询的整个响应。如果提交另一个查询(对同一查询使用不同的语句连接),驱动程序缓存对第一个在提交第二个查询之前进行查询。通常,直接法比游标方法执行得更好。
如果设置为游标,则会请求服务器端游标。返回时仅转发结果集,从中的服务器检索行块。setFetchSize()方法可用于控制仅转发结果集时为每个请求检索的行返回。性能测试表明,当仅向前返回时结果集,Statement.setFetchSize()的值影响性能。没有简单的规则来确定setFetchSize()值。我们建议您使用不同的setFetchSize()值进行实验,以确定value为您的应用程序提供最佳性能。光标方法对于生成大量数据的查询是有用的,特别是在使用多个开放结果集的情况下。
请考虑以下摘录自用户指南和参考手册:
SelectMethod:在大多数情况下,使用服务器端数据库游标对性能产生负面影响。但是,如果以下变量对于应用程序为true,则此属性的最佳设置为游标,这意味着使用服务器端数据库游标:
- 您的应用程序包含检索大量数据的查询
- 您的应用程序在处理或关闭以前的大型结果集之前执行SQL语句,并执行多次
- 应用程序返回的大型结果集使用仅向前的游标
请注意,查询数据后,blob将作为代理进行检索,并准备从中读取流。在关闭连接之前,您可能需要检查是否已从中读取(可能是byte[])数据。当然,根据您的情况,您似乎会在某个时候以某种方式关闭连接,但这并不清楚,但读取内存中的数据而不是只持有代理,可以确保关闭会话/连接的安全性,不会给代理带来这样的问题,因为数据已经被读取。
在检索大量数据并在完成之前的所有数据检索之前执行查询的情况下,游标解决方案是有益的,这可能是这里的问题。因此,这也被认为是另一种选择,而无需将数据急切地加载到内存中,并且完全避免代理。
我认为这是一个Hibernate varbinary列编码问题,如下所示进行更改表具有:ENGINE=InnoDB DEFAULT CHARSET=utf8;Hibernate属性具有:
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
https://www.experts-exchange.com/questions/28131390/Hibernate-varbinary-colum-encoding-issue.html
如您在https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbcMS-SQL JDBC驱动程序对不同的JRE版本有不同的版本(以.jre17、.jre11、.jre8等结尾的版本)
当我将MS-SQLJDBC驱动程序的.jre7版本的渐变依赖项复制到JRE 17项目中时,我遇到了这个错误。
一旦我将gradle依赖项更改为JRE 17版本,错误就消失了。