2

我的应用程序使用 JPA(Hbernate ORM) 连接到部署在 JBoss AS 7.x 服务器中的 SQL server 2008 。如果网络出现故障并再次出现,我会收到以下异常

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>

你能告诉我,如果网络出现故障并重新连接,如何重新连接到数据库?

4

3 回答 3

6

你可以添加

<check-valid-connection-sql>select 1 </check-valid-connection-sql>

到您的数据源配置或您想要的任何其他 sql 语句。每次从连接池中检出连接时都会执行此 sql 语句,如果语句失败,即连接已关闭,它将被销毁并重新创建/重新连接到 sql server。这将确保您的应用程序(休眠)始终获得有效的 sql 连接。

于 2012-11-02T01:04:22.413 回答
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>
于 2014-04-04T07:43:36.940 回答
2

你想解决什么问题?

如果您试图在“网络出现故障”时阻止交易失败。那是不可能的。您需要研究“XA”和 SQL 集群来解决该问题的某些部分。但我不认为你在寻找这个。

..

如果您想阻止应用程序操作失败,如果它们不幸成为空闲 SQL 连接的第一个用户,则 JBoss 中的连接池保持。那么是的,您可以做一些事情。

问题是:

  • 默认情况下,当“网络出现故障”时,Windows 会断开活动的 TCP 连接,而其他平台不这样做。对你来说,我猜只有一部分网络出现故障,这意味着如果受影响的是 SQL 服务器端,而不是 JBoss 端。

  • JBoss 端的连接池将保持 TCP 连接打开,池中有空闲连接。JBoss端不知道网络宕机了,可能会与SQL server短时间失去联系。当网络出现时,SQL 服务器端重置/丢失所有连接。但是 JBoss 端仍然有“半开连接”,它仍然认为连接是有效的。

  • 在需要处理 SQL 之前,JBoss 端可能会空闲一段时间(秒/分钟/小时)。然后它去获取一个 SQL 句柄,连接池程序适当地从空闲的池中返回一个。不知道 TCP 连接已死。然后,应用程序使用它来发现 TCP 连接被重置以响应从客户端发送到服务器和服务器说“我没有打开那个连接”的一些数据。这会强制 SQL 驱动程序关闭连接并开始向 JDBC 句柄上的操作返回 SQLException。

因此,下面我将笼统地谈论如何帮助缓解或解决问题,请查阅您的支持渠道和 SQL 文档:

要调查的事情:

  • 您的连接池文档。我相信 JBoss 提供了自己的连接池实现。因此,虽然这个问题确实可以在连接池中解决,但尚不清楚您的 JBoss 版本和您已经使用的连接池是否具有这些功能。

  • 启用 TCP keepalives,这些是由 TCP 协议执行的低级 ping/pong,通常可以在几秒内完成。默认值可能是 1 小时,这对于 SQL 来说太长了,可能 5 分钟更好。

  • 在将连接提供给应用程序之前,启用连接池检查/验证连接是否良好且有效。这可能会使用内部 ping/pong 检查或可能会执行“SELECT 1”。这可能是完全解决问题的最简单/最快的解决方案,但是在使用前额外的往返行程可能会对性能产生可衡量的影响。

  • 仅当连接空闲时间超过某个限制(可能为 60 秒)时才启用上述点。这减轻了在 SQL 非常空闲时启用它对性能的影响。

  • 查看您的 SQL 驱动程序是否支持自定义 TCP 数据 ping/pong 机制,并查看连接池实现是否支持使用它。

  • 使用较短的最大空闲时间。

  • 降低最大空闲连接数。

  • 如果连接不在事务中并且这是第一个失败的语句,则启用自动重新连接(通常唯一的选项更改是 autocommit=off 然后 'BEGIN TRANSACTION' 驱动程序可以检测到这种情况并从中无缝恢复) .

如果您可以选择使用外部 3rd 方开源池程序,建议可能会查看 c3p0 连接池程序。在 JBoss 环境中可能不是这种情况。

于 2012-10-25T10:37:17.133 回答