java - Tomcat + Hibernate + JNDI + Azure DB - 连接被对等方重置 : socket write error

标签 java hibernate tomcat azure

这里有一个错误让我发疯,它似乎有大量相关条目,但到目前为止还没有解决方案。也许我的配置有一些特殊的东西我到目前为止还没有发现......

我正在运行 Java 应用程序,使用 Hibernation (5.0.3.Final) 通过 JNDI 资源 (tomcat 8.0.28) 连接 Azure SQL DB (v12)。 我收到(看起来随机)连接由对等方重置:套接字写入错误,然后是连接已关闭错误。该应用程序只有重新启动才能恢复...

尽管我已经配置了 validationQuery 并且还设置了 testOnCreatetestOnBorrowtestWhileIdle,但还是发生了这种情况为真。

下面我将给您完整的配置。这真的让我发疯,因为这似乎是一个众所周知的错误,但多年来一直没有解决?!

这是配置:

server.xml:

 <Resource name="jdbc/booking"
     global="jdbc/booking"
     auth="Container"
     username="XXX"
     password="YYY"
     type="javax.sql.XADataSource"
     driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
     url="jdbc:sqlserver://mydatabase.database.windows.net:1433;database=booking;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;"
     factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
     maxWait="10000"
     validationQuery="SELECT 1"
     testOnCreate="true"
     testOnBorrow="true"
     testWhileIdle="true"
     timeBetweenEvictionRunsMillis="30000"
     minEvictableIdleTimeMillis="60000"
     validationInterval="1000"
     removeAbandonedOnMaintenance="true"
     fastFailValidation="true"/>

context.xml(在 war 的 web/META-INF/中)

<ResourceLink name="jdbc/booking" global="jdbc/booking"/> 

hibernate.cfg

<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="connection.datasource">java:comp/env/jdbc/booking</property>

我正在设置 Hibernate session 工厂,如下所示:

private void setUp() {
    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure( AzureDB.configFile ).build();
    try {
        this.sessionFactory = new MetadataSources( registry ).buildMetadata().buildSessionFactory();
    } catch ( final Exception e ) {
        System.err.println( e.getMessage() );
        StandardServiceRegistryBuilder.destroy( registry );
        System.exit( 666 );
    }
}

并通过在我的服务中注入(inject)来使用它,如下所示:

@Inject private AzureDB           bookingDB;

...

this.bookingDB.getCurrentSession().beginTransaction();
final Hotel hotel = this.bookingDB.getCurrentSession().get( Hotel.class, hotelId );

一个请求将成功完成,下一个请求将遇到 Connection Rest by Peer 错误。完整的 stracktrace 将如下所示:

16-Nov-2015 09:26:59.028 WARN [http-apr-8080-exec-13] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions SQL Error: 0, SQLState: 08S01
16-Nov-2015 09:26:59.028 ERROR [http-apr-8080-exec-13] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions Connection reset by peer: socket write error
16-Nov-2015 09:26:59.044 INFO [http-apr-8080-exec-13] org.hibernate.event.internal.DefaultLoadEventListener.onLoad HHH000327: Error performing load command : org.hibernate.exception.JDBCConnectionException: could not extract ResultSet
16-Nov-2015 09:26:59.060 SEVERE [http-apr-8080-exec-13] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [com.nekst.service.nekstAPI] in context with path [] threw exception [org.hibernate.exception.JDBCConnectionException: could not extract ResultSet] with root cause
 com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset by peer: socket write error
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1748)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1732)
    at com.microsoft.sqlserver.jdbc.TDSChannel.write(IOBuffer.java:1842)
    at com.microsoft.sqlserver.jdbc.TDSWriter.flush(IOBuffer.java:4161)
    at com.microsoft.sqlserver.jdbc.TDSWriter.writePacket(IOBuffer.java:4062)
    at com.microsoft.sqlserver.jdbc.TDSWriter.endMessage(IOBuffer.java:3107)
    at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:6700)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:424)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:372)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:6276)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1793)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:184)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:159)
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:284)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:433)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:185)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:120)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:85)
    at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3954)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:488)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:453)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:196)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:258)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:134)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1071)
    at org.hibernate.internal.SessionImpl.access$2600(SessionImpl.java:164)
    at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2638)
    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:955)
    at sun.reflect.GeneratedMethodAccessor160.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:338)
    at com.sun.proxy.$Proxy138.get(Unknown Source)
    at com.nekst.service.rest.Kauai.getLocation(Kauai.java:227)
    at com.nekst.service.rest.Kauai.getRecommendation(Kauai.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
    at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:471)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:425)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:383)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:336)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:223)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at com.googlecode.psiprobe.Tomcat80AgentValve.invoke(Tomcat80AgentValve.java:45)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2503)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2492)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

后跟com.microsoft.sqlserver.jdbc.SQLServerException:连接已关闭。任何后续请求。

可能会有数周的不受干扰的服务,然后(就像目前一样)我不断地看到此错误...有人在这种具体设置中经历过或对我的情况有任何其他评论吗?非常感谢您的帮助...

更新:我还尝试按照此处的建议添加自定义注册表项:https://msdn.microsoft.com/en-us/library/hh290696(v=SQL.110).aspx ,不走运,我可以在wireshark中看到keepalive,但仍然出现这些错误

最佳答案

根据我的经验,该问题通常是由于 JNDI 中的 JDBC 连接池配置不合适造成的。

有一个关于 Azure SQL 数据库资源限制的官方文档 https://azure.microsoft.com/en-us/documentation/articles/sql-database-resource-limits/ .

我检查了您的 JNDI 配置。因此,我建议您可以引用 Azure 服务层的限制和 JNDI https://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html#JDBC_Data_Sources 中的 JDBC 数据源设置的 Tomcat 文档。将配置属性 initialSizemaxActiveminIdlemaxIdle 设置为合适的值,例如 maxIdle=100 .

更新:enter image description here

initialSizeminIdle 默认值为 0。minIdle 属性控制池释放连接时的​​最小连接数。并发访问。如果池连接释放到0,新的访问会导致连接重置问题。

更新于2015年11月19日:

有一段摘录解释了该问题连接被对等方重置

[10054] Connection reset by peer

Connection reset by peer is a tough one because it can be caused by so many things. In all cases, the server determines that the socket is no longer good and closes it from its side.

Write Error

Scenario: Mary was trying to talk to Joe but didn't think she was getting through, so she hung rather than lose his messages (data). A write error occurs when a server cannot successfully write to a user's client. When the server receives information, it usually responds with information of its own. When the server receives an error when writing to a client, it then disconnects the user, resulting in a write error quit message similar to the read error format.

关于java - Tomcat + Hibernate + JNDI + Azure DB - 连接被对等方重置 : socket write error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33732582/

相关文章:

tomcat - 将 tomcat 集成到 siteminder

java - 使用 .keystore 文件为 tomcat 8.5 配置 SSL - 无法存储非私钥

java - 从 java 代码启动 javaFX 应用程序

java - 从 hibernate session 中删除对象

java - 已弃用 SequenceHiLoGenerator 基于序列的 id 生成器;使用 SequenceStyleGenerator 代替

java - Spring + Hibernate + Redis 的分布式锁

java - Tomcat 中的 Quartz 调度程序内存泄漏

java - 使用堆栈检查 .txt 文件中的 ('s, {' s、[ 等 - Java

Java:无法使用 MySQL 中的 "USE"关键字?

包含生成的 JSTL : not interpreted 的 Java 自定义标记