c3p0 在无法到达主机时不会超时

c3p0 do not timeout when are impossible to reach the host

我的程序在打开时做的第一件事是尝试连接数据库,如果 c3p0 无法连接,它会冻结并且不会引发任何错误消息。

奇怪的是,使用 MySql 我得到了 java.net.UnknownHostException,但是使用 SqlServer 什么都没有,它一直在努力。

我想捕捉错误并做点什么。我尝试设置此属性但没有成功。

<property name="hibernate.c3p0.timeout" value="60"/>
<property name="hibernate.c3p0.unreturnedConnectionTimeout" value="60"/>

我的persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.lala.Something</class>
        <shared-cache-mode>NONE</shared-cache-mode>
        <properties>
            <!-- connection -->
            <property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=str"/>
            <property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
            <property name="javax.persistence.jdbc.user" value="teste"/>
            <property name="javax.persistence.jdbc.password" value="teste"/>
            <!-- hibernate -->
            <property name="hibernate.format_sql" value="false"/>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.use_sql_comments" value="false"/>
            <!-- c3p0 -->
            <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
            <property name="hibernate.c3p0.min_size" value="1"/>
        </properties>
    </persistence-unit>
</persistence>

如果 c3p0 尝试从数据库获取连接,而那些获取尝试 "hang"——它们既不成功也不失败并出现异常——那就糟糕了。挂起的获取最终会使线程池饱和,迫使它声明一个 APPARENT DEADLOCK 并自行重建。

您尝试设置的两个属性均与此问题无关。如果您想解决这些挂起问题,要查看的 c3p0 配置 属性 将是 maxAdministrativeTaskTime.

我决定添加这两个属性:

获取重试次数

定义 c3p0 在放弃之前尝试从数据库获取新连接的次数。如果此值小于或等于零,c3p0 将无限期地继续尝试获取连接。

breakAfterAcquireFailure

如果为 true,如果在进行 acquireRetryAttempts 后无法从数据库中获取连接,则合并的数据源将声明自己已损坏并永久关闭。如果为false,获取Connection失败将导致所有等待池中获取Connection的Thread抛出Exception,但DataSource会保持有效,并会在调用getConnection()后再次尝试获取。

        <property name="hibernate.c3p0.acquireRetryAttempts" value="3"/>
        <property name="hibernate.c3p0.breakAfterAcquireFailure" value="true"/>

虽然 accepted 有助于将尝试 "acquire" 连接的次数从 30 (!) 减少到 3,但如果服务器没有响应,getConnection() 仍然会 "hang" 很长时间.似乎 c3p0 使用 "check out/in" 的不同命名法将连接添加到池中。因此,将 checkoutTimeout 设置为 0 以外的值(永远等待!)可以解决问题。

我猜测 acquireRetryAttempts 和 checkoutTimeout 已应用于每个 intialPoolSize 连接。