Spring应用(Hibernate+C3P0)连接PostgreSQL报UnknownHostException排查
问题场景
我有一个基于Spring(Hibernate+C3P0)的应用,原本能正常连接Oracle数据库,切换到PostgreSQL时却抛出java.net.UnknownHostException错误。
applicationContext中的数据源配置如下:
<bean id="appDS" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="org.postgresql.Driver" /> <property name="jdbcUrl" value="jdbc:postgresql://THE_SERVER:5432/schema" /> <property name="user" value="appc0" /> <property name="password" value="THE_PWD" /> </bean>
我在同一服务器上用简易Java应用做了连接测试,代码如下,测试完全正常,排除了网络、数据库地址、账号密码及驱动的问题:
public static void main(String[] args) { try { System.out.println("TEST Driver Manager START"); Class.forName("org.postgresql.Driver"); String url = "jdbc:postgresql://THE_SERVER:5432/schema"; String user = "appc0"; String passwd = "THE_PWD"; Connection conn = DriverManager.getConnection(url, user, passwd); System.out.println("Schema : " + conn.getSchema()); System.out.println("ClientInfo : " + conn.getClientInfo()); System.out.println("TEST Driver Manager END"); System.out.println("TEST C3P0 START"); ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass( "org.postgresql.Driver" ); cpds.setJdbcUrl( "jdbc:postgresql://THE_SERVER:5432/schema" ); cpds.setUser("appc0"); cpds.setPassword("THE_PWD"); System.out.println("User :"+ cpds.getUser()); System.out.println("TEST C3P0 END"); } catch(Exception e) { e.printStackTrace(); } }
使用版本:postgresql-42.2.0.jre7.jar、c3p0-0.9.1.2.jar
问题分析与解决方案
结合你的测试结果(独立应用正常,Spring应用报错),核心问题基本锁定在Spring环境的配置加载或优先级冲突上,给你几个具体的排查方向:
1. 检查配置占位符是否未正确解析
你配置里的THE_SERVER如果是占位符(比如${db.host}),但Spring没有正确加载对应的属性文件,就会导致实际连接URL是字面量THE_SERVER,而非真实服务器地址,直接触发UnknownHostException。
- 验证方式:在Spring应用启动后,获取
appDSbean,调用getJdbcUrl()方法打印实际的连接地址,确认是否是正确的服务器域名/IP。 - 修复:确保PropertyPlaceholderConfigurer配置正确,对应的属性文件(比如
application.properties)中存在db.host的正确配置,且属性文件已被Spring加载。
2. 排查C3P0的全局配置覆盖问题
C3P0会读取全局配置文件(如c3p0.properties或c3p0-config.xml)中的参数,优先级可能高于Spring bean中的配置。如果你的项目classpath下存在这些文件,且里面配置的c3p0.jdbcUrl是错误地址,就会覆盖Spring的配置。
- 验证方式:检查项目根目录或resources目录下是否存在
c3p0.properties/c3p0-config.xml,查看其中的jdbcUrl配置。 - 修复:删除或修改全局配置文件中的错误参数,确保和Spring bean配置一致。
3. 确认Hibernate是否引用了正确的数据源
如果Hibernate的配置文件(如hibernate.cfg.xml)中硬编码了Oracle的连接参数,或者没有正确引用appDS这个数据源bean,就会导致Hibernate没有使用你配置的PostgreSQL数据源。
- 验证方式:检查
hibernate.cfg.xml,确认是否存在<property name="hibernate.connection.datasource">appDS</property>这样的配置,而不是单独配置hibernate.connection.url等参数。 - 修复:修改Hibernate配置,确保它依赖Spring中的
appDS数据源。
4. 排查类加载器导致的版本冲突
虽然测试应用用了正确版本的jar,但Spring应用所在的服务器(如Tomcat)的lib目录可能存在旧版本的PostgreSQL驱动或C3P0 jar,导致类加载器加载了错误的版本,进而引发配置不生效。
- 验证方式:检查应用服务器的lib目录,查看是否有
postgresql-*.jar或c3p0-*.jar,对比版本是否和你项目中的一致。 - 修复:移除服务器lib目录中冲突的jar包,确保应用使用的是项目中打包的正确版本。
快速验证技巧
在Spring应用中添加一个测试bean,手动初始化C3P0数据源(和你测试应用中的代码一致),放在bean的@PostConstruct方法中执行:
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.sql.Connection; @Component public class DataSourceTest { @PostConstruct public void testManualC3P0() { try { System.out.println("Spring Context内测试C3P0 START"); ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass("org.postgresql.Driver"); cpds.setJdbcUrl("jdbc:postgresql://THE_SERVER:5432/schema"); cpds.setUser("appc0"); cpds.setPassword("THE_PWD"); Connection conn = cpds.getConnection(); System.out.println("连接成功,Schema:" + conn.getSchema()); System.out.println("Spring Context内测试C3P0 END"); } catch (Exception e) { e.printStackTrace(); } } }
如果这个测试能成功,那100%是Spring配置加载的问题,重点排查前两个方向;如果失败,再考虑类加载器或环境差异的问题。
内容的提问来源于stack exchange,提问作者user2007861

