我的应用程序使用JPA(Hbernate ORM)连接到SQL Server 2008,它部署在JBoss AS 7.x服务器中。如果网络出现故障并再次出现,我将收到以下异常
14:59:27,996 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: The connection is closed.
14:59:28,002 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1361)
14:59:28,012 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1289)
14:59:28,020 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:261)
14:59:28,025 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at com.honeywell.domoweb.dataservice.dao.impl.UserDaoImpl.getUsers(UserDaoImpl.java:372)
14:59:28,030 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
14:59:28,034 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
14:59:28,039 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
14:59:28,044 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at java.lang.reflect.Method.invoke(Method.java:597)
14:59:28,047 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
14:59:28,052 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
14:59:28,058 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
14:59:28,064 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
14:59:28,069 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
14:59:28,075 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
14:59:28,080 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at $Proxy66.getUsers(Unknown Source)
14:59:28,083 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at com.honeywell.domoweb.dataservice.dao.impl.TemplateDaoImpl.getTemplate(TemplateDaoImpl.java:44)
14:59:28,089 ERROR [stderr] (http-localhost-127.0.0.1-8080-1) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)...
我搜索了这个问题并发现此问题需要更改连接池配置以使用autoReconnect属性重新连接,但没有找到任何示例,如何使用我的连接池设置嵌入autoReconnect。我是Standalone.xml文件中的连接池设置
<subsystem xmlns="urn:jboss:domain:datasources:1.0">
<datasources>
<datasource jndi-name="java:jboss/datasources/DataServiceDS" pool-name="dataServicePool" enabled="true" use-java-context="true">
<connection-url>jdbc:sqlserver://ipaddress:1433;databaseName=myDataBase</connection-url>
<driver>sqlserver</driver>
<pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>100</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>usename</user-name>
<password>password</password>
</security>
</datasource>
<drivers>
<driver name="sqlserver" module="com.microsoft.sqlserver">
<xa-datasource-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
如果网络出现故障并重新连接,请告诉我如何重新连接到数据库?
答案 0 :(得分:6)
你可以添加
<check-valid-connection-sql>select 1 </check-valid-connection-sql>
到您的数据源配置或您想要的任何其他sql语句。 每次从连接池检出连接时都会执行此sql语句,如果语句失败,即连接已关闭,则会被销毁并重新创建/重新连接到sql server。这将确保您的应用程序(休眠)始终可以使用sql连接。
答案 1 :(得分:3)
也很难找到类似问题的例子。对于jboss7,将以下行添加到数据源配置
<datasource>
...
<validation>
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
<validate-on-match>false</validate-on-match>
<background-validation>true</background-validation>
</validation>
...
</datasource>
答案 2 :(得分:2)
你想要修复什么?
如果您尝试在“网络中断”时阻止事务失败。那是不可能的。您需要查看“XA”和SQL集群来解决该问题的某些部分。但我不认为你在寻找这个。
...
如果你想让应用程序操作失败,如果他们不幸成为空闲SQL连接的第一个用户,那么JBoss中的连接池将保持不变。那么是的,你可以做些什么。
问题是:
Windows默认情况下会在“网络中断”时断开活动的TCP连接,而其他平台则不会这样做。对你来说,我猜只有网络的一部分出现故障,这意味着如果受影响,SQL服务器端会结束,而不是JBoss端。
JBoss端的连接池将保持TCP连接打开,池中有空闲连接。 JBoss端不知道网络出现故障,可能会在短时间内与SQL Server失去联系。当网络启动时,SQL Server端重置/丢失所有连接。但是JBoss端仍然具有“半开连接”,它仍然认为连接是有效的。
JBoss端可能需要空闲一段时间(秒/分钟/小时)才能使用SQL。然后它将获得一个SQL句柄,连接池将从空闲的池中正确返回一个。不知道TCP连接已经死了。然后,应用程序使用它来查找TCP连接被重置以响应从客户端发送到服务器和服务器的一些数据,说“我没有打开该连接”。这会强制SQL驱动程序关闭连接并开始将SQLException返回到JDBC句柄上的操作。
下面我将概述如何帮助缓解或解决问题,请参阅您的支持渠道和SQL文档:
要研究的事项:
您的连接pooler文档。我相信JBoss提供了自己的连接池实现。因此,虽然确实可以通过连接池来解决这个问题,但是不清楚与JBoss版本的连接是否正常,而您已经使用的那个可能具有适当的功能。
启用TCP keepalive,这些是TCP协议执行的低级别ping / pong,通常可以在几秒钟内完成。对于SQL来说,默认值可能是1小时,这可能是5分钟更好。
在将连接提供给应用程序之前,启用连接池以检查/验证连接是否良好且有效。这可能使用内部ping / pong检查或可能'SELECT 1'。这可能是解决问题的最简单/最快的解决方案,但是在使用前额外往返可能会对性能产生可测量的影响。
仅当连接空闲时间超过某个限制(可能为60秒)时才启用上述要点。这可以减轻在SQL非常闲置时启用它的性能影响。
查看您的SQL驱动程序是否支持自定义TCP数据ping / pong机制,并查看连接池实现是否支持使用它。
使用较短的最长空闲时间。
降低最大空闲连接数。
如果连接不在事务中,则启用自动重新连接,如果这是第一个失败的语句(通常唯一的选项更改是autocommit = off,那么'BEGIN TRANSACTION'这种情况对于驱动程序来说是可能的检测并无缝恢复。
如果您可以选择使用外部第三方开源池,则可以查看c3p0连接池。在JBoss环境中可能不是这种情况。