2017-04-07 30 views
1

我正在寫一個應用程序,它通過Hibernate與c3p0池連接到Postgres數據庫。在主界面顯示之前,我想檢測任何有效的數據庫連接設置並連接到DB。如果設置無效,我想向用戶顯示一條消息,並建議更改設置或關閉應用程序。 但問題是,EntityManagerFactory將不會拋出一個異常,甚至不成功的連接後返回。JPA,與c3p0和Postgres一起休眠。檢測數據庫連接問題

下面是代碼的例子,其與錯誤連接設置產生一個錯誤:

public void connect(ConnectionSettingsModel conSet) throws Exception { 
    Map<String, String> connectionProperties = new HashMap<>(); 
    connectionProperties.put("javax.persistence.jdbc.url", conSet.getUrl()); 
    connectionProperties.put("javax.persistence.jdbc.user", conSet.getUser()); 
    connectionProperties.put("javax.persistence.jdbc.password", conSet.getPassword()); 
    connectionProperties.put("hibernate.default_schema", conSet.getSchema()); 

    System.out.println("Before creating EM"); 
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("postgres-connect", connectionProperties); 
    EntityManager entityManager = entityManagerFactory.createEntityManager(); 
    System.out.println("After creating EM"); 
} 

C3P0配置在persistence.xml

<property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/> 
<property name="hibernate.c3p0.min_size" value="0"/> 
<property name="hibernate.c3p0.max_size" value="10"/> 
<property name="hibernate.c3p0.timeout" value="300"/> 
<property name="hibernate.c3p0.idle_test_period" value="3000"/> 
<property name="hibernate.c3p0.max_statements" value="50"/> 
<property name="hibernate.c3p0.acquireRetryAttempts" value="1"/> 

與不存在的用戶名的日誌示例:

Before creating EM 
14:47:07,009 INFO [com.mchange.v2.log.MLog] - MLog clients using log4j logging. 
14:47:07,239 INFO [com.mchange.v2.c3p0.C3P0Registry] - Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] 
14:47:07,303 INFO [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] - Initializing c3p0 pool... [email protected] [ connectionPoolDataSource -> [email protected] [ acquireIncrement -> 3, acquireRetryAttempts -> 1, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, debugUnreturnedConnectionStackTraces -> false, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, identityToken -> 1hge3hi9nk1ku80noopkx|3185ce3, idleConnectionTestPeriod -> 3000, initialPoolSize -> 0, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 300, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 50, maxStatementsPerConnection -> 0, minPoolSize -> 0, nestedDataSource -> [email protected] [ description -> null, driverClass -> null, factoryClassLocation -> null, forceUseNamedDriverClass -> false, identityToken -> 1hge3hi9nk1ku80noopkx|26e664, jdbcUrl -> jdbc:postgresql://localhost:5432/postgres, properties -> {user=******, password=******} ], preferredTestQuery -> null, privilegeSpawnedThreads -> false, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false; userOverrides: {} ], dataSourceName -> null, extensions -> {}, factoryClassLocation -> null, identityToken -> 1hge3hi9nk1ku80noopkx|3d02a858, numHelperThreads -> 3 ] 
квіт. 07, 2017 2:47:07 PM org.postgresql.Driver connect 
SEVERE: Connection error: 
    org.postgresql.util.PSQLException: FATAL: password authentication failed for user "user" 
    --code omitted 
квіт. 07, 2017 2:47:07 PM org.postgresql.Driver connect 
SEVERE: Connection error: 
    org.postgresql.util.PSQLException: FATAL: password authentication failed for user "user" 
    --code omitted 
    -- few attempts to connect 
14:47:55,009 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - Having failed to acquire a resource, [email protected] is interrupting all Threads waiting on a resource to check out. Will try again in response to new client requests. 

此消息後,它不會拋出任何異常或r E打開

回答

1

你可能會考慮修改

<property name="hibernate.c3p0.acquireRetryAttempts" value="1"/> 

回到它的30默認(或者更高),然後嘗試

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

然後,如果嘗試獲取從連接的完整週期數據庫失敗(同樣,這應該不止一次,或者您的應用程序將非常脆弱),您的c3p0 DataSource將會中斷,並且進一步嘗試檢出Connection將立即失敗。這樣做的缺點是你會在臨時網絡或數據庫中斷後失去c3p0的「自我修復」能力。如果臨時中斷在採集週期中失敗,則必須自己重新構建數據源(或重新啓動應用程序)。

如果你想兩全其美的,設置hibernate.c3p0.acquireRetryAttempts回30十歲上下,離開hibernate.c3p0.breakAfterAcquireFailure它的false默認,但寫自己的自定義代碼來測試你的數據庫的可用性。修改您的測試connect()功能上面(這需要重組,你只需要創建EntityManagerFactory一次),可能是那樣簡單......

public void connect(ConnectionSettingsModel conSet) throws Exception { 

    try(Connection con = DriverManager.getConnection(conSet.getUrl(), conSet.getUser(), conSet.getPassword())) { 
     /* Nothing to do here, really... */ 
    } catch (Exception e) { 
     System.out.println("Trouble connecting with DBMS, please check database url, username, and password."); 
     throw e; 
    } 

    Map<String, String> connectionProperties = new HashMap<>(); 
    connectionProperties.put("javax.persistence.jdbc.url", conSet.getUrl()); 
    connectionProperties.put("javax.persistence.jdbc.user", conSet.getUser()); 
    connectionProperties.put("javax.persistence.jdbc.password", conSet.getPassword()); 
    connectionProperties.put("hibernate.default_schema", conSet.getSchema()); 


    System.out.println("Before creating EM"); 
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("postgres-connect", connectionProperties); 
    EntityManager entityManager = entityManagerFactory.createEntityManager(); 
    System.out.println("After creating EM"); 
} 
+0

我試圖解決這個問題的線程,但你的解決方案似乎更加緊湊和簡單。將你的第三個解決方案壓縮成'DriverManager.getConnection(conSet.getUrl(),conSet.getUser(),conSet.getPassword())。close()' – AndriiL

+0

很簡潔! –