Spring Boot+Hibernate+Postgres每次请求新建数据库连接的原因及配置方案
场景回顾
我搭建了一套Java-Spring Boot-Hibernate-Postgres应用,发现Hibernate会在每次请求时创建新的数据库连接。我的Hibernate配置如下:
@Autowired private Environment environment; @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); sessionFactory.setPackagesToScan(new String[] { "monitoring" }); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setUrl(environment.getRequiredProperty("spring.datasource.url")); dataSource.setUsername(environment.getRequiredProperty("spring.datasource.username")); dataSource.setPassword(environment.getRequiredProperty("spring.datasource.password")); return dataSource; } private Properties hibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", environment.getRequiredProperty("spring.jpa.properties.hibernate.dialect")); properties.put("hibernate.show_sql", environment.getRequiredProperty("spring.jpa.hibernate.show-sql")); properties.put("hibernate.format_sql", "false"); properties.put("hibernate.jdbc.lob.non_contextual_creation", "true"); return properties; }
每次请求都会生成如下日志:
11:19:13.584 [http-nio-8080-exec-2] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:postgresql://localhost:5432/monit]
请问该现象的原因是什么?如何修改配置解决?是否可以设置会话持续10分钟?
原因分析
你当前使用的DriverManagerDataSource是Spring提供的最简单的数据源实现,它完全没有连接池功能——每次调用getConnection()方法时,都会直接新建一个JDBC连接,用完后就立即关闭。这就是你每次请求都能看到新建连接日志的核心原因,这种方式在生产环境会带来极大性能开销,因为数据库连接的创建和销毁是非常耗资源的操作。
Spring Boot默认会自动配置高性能的连接池(比如HikariCP,目前是Spring Boot的官方默认选择),但你手动定义了DriverManagerDataSource的Bean,覆盖了默认的连接池配置,导致连接复用机制完全没有生效。
解决方案:启用连接池并配置参数
方案1:使用Spring Boot自动配置(推荐)
直接删除你自定义的dataSource() Bean,然后在application.properties或application.yml中配置数据源和连接池参数即可,Spring Boot会自动帮你创建高性能的HikariDataSource:
application.properties示例:
# 基础数据源配置 spring.datasource.url=jdbc:postgresql://localhost:5432/monit spring.datasource.username=你的数据库用户名 spring.datasource.password=你的数据库密码 spring.datasource.driver-class-name=org.postgresql.Driver # HikariCP连接池配置(对应你要的"会话持续10分钟",这里配置空闲连接保留时间) spring.datasource.hikari.maximum-pool-size=10 # 连接池最大连接数 spring.datasource.hikari.minimum-idle=2 # 保持池中有足够的空闲连接,避免频繁创建 spring.datasource.hikari.connection-timeout=30000 # 获取连接的超时时间(30秒) spring.datasource.hikari.idle-timeout=600000 # 空闲连接超时时间(10分钟,超过则自动回收) spring.datasource.hikari.max-lifetime=1800000 # 连接最大存活时间(30分钟,避免长期占用连接)
方案2:手动配置HikariDataSource
如果你需要保持自定义Bean的方式,可以把DriverManagerDataSource替换为HikariDataSource:
@Autowired private Environment environment; @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setDriverClassName("org.postgresql.Driver"); dataSource.setJdbcUrl(environment.getRequiredProperty("spring.datasource.url")); dataSource.setUsername(environment.getRequiredProperty("spring.datasource.username")); dataSource.setPassword(environment.getRequiredProperty("spring.datasource.password")); // 连接池核心配置 dataSource.setMaximumPoolSize(10); dataSource.setMinimumIdle(2); dataSource.setConnectionTimeout(30000); dataSource.setIdleTimeout(600000); // 10分钟空闲超时 dataSource.setMaxLifetime(1800000); return dataSource; } // 其他sessionFactory和hibernateProperties配置保持不变
关于"会话持续10分钟"的说明
你提到的"会话持续10分钟"需要明确两个核心概念:
- 数据库连接的复用:上面配置的
idleTimeout是控制连接池中空闲连接的保留时间,超过10分钟的空闲连接会被自动回收,而不是让连接一直占用。连接池的核心作用是复用连接,每次请求会从池中获取空闲连接,用完后归还,避免重复创建销毁连接的开销。 - Hibernate Session的生命周期:Hibernate Session默认是和请求绑定的(比如Open Session in View模式),请求结束后Session就会关闭并释放连接。如果要让Session持续10分钟,这并不推荐——因为Session是线程不安全的,长期持有会导致连接泄漏和并发问题。通常我们通过连接池来管理连接的复用,而不是延长Session的生命周期。
内容的提问来源于stack exchange,提问作者thehespe

