我有一个带有Hibernate和Hikari DataSource的Spring Boot项目。 如果我有一些注入SessionFactory对象的功能来获取会话对象,那么在几天内我就会遇到与db操作相关的任何方法的异常(只有重启才能解决这个问题):
org.springframework.transaction.CannotCreateTransactionException:
Could not open JPA EntityManager for transaction; nested exception is
javax.persistence.PersistenceException:
org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection at
......
Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 -
Connection is not available, request timed out after 30001ms.
似乎手动使用会话会产生这个问题。 (我有相同的配置和功能的类似项目,但没有注入SessionFactory和Session ......我根本没有这样的问题)
application.yaml :
spring:
jpa:
properties:
hibernate:
dialect : org.hibernate.dialect.PostgreSQLDialect
current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
DataSourceConfig
@EnableJpaRepositories("com.my.project.config")
@Configuration
public class DataSourceConfig {
@Inject
private AppProperties properties;
@Bean(name = "dataSource")
public DataSource dataSource() {
AppProperties.DatabaseProperties dbProps = properties.getDatabaseProperties();
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(org.postgresql.Driver.class.getName());
dataSource.setJdbcUrl(
dbProps.getProtocol().concat("://")
.concat(dbProps.getDbHost()).concat(":")
.concat(dbProps.getDbPort()).concat("/")
.concat(dbProps.getDbname())
);
dataSource.setUsername(dbProps.getUsername());
dataSource.setPassword(dbProps.getPassword());
dataSource.setMaximumPoolSize(30);
dataSource.setMinimumIdle(30);
return dataSource;
}
@Bean
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
return hemf.getSessionFactory();
}
}
LogRepositoryImpl
@Repository
public class LogRepositoryImpl implements LogRepository {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Log> getLogs(int offset, int count) {
Criteria criteria = getSession().createCriteria(Log.class);
return criteria.setFirstResult(offset).setMaxResults(count).list();
}
@Override
public void save(Log log) {
getSession().save(log);
}
private Session getSession() {
return sessionFactory.getCurrentSession();
}
}
dataSource.setMaximumPoolSize(30), dataSource.setMinimumIdle();没有解决这个问题
答案 0 :(得分:0)
听起来像是您的事务边界问题,它不会将连接释放回池中。您可以尝试将@Transactional
放在LogRepositoryImpl
课程上吗?
@Repository
@Transactional
public class LogRepositoryImpl implements LogRepository {
. . .
}
答案 1 :(得分:0)
我们最近遇到了这个问题,但连接池错误消息最终只是诱饵。
真正的问题是第三方系统不接受更多消息,从而阻塞了每个线程。如果线程之前从 HikariCP 获取了连接,则连接永远不会返回到池中。因此,我们的成功连接数与池化连接数一样多。
在这种情况下:使用选择的工具(任何 APM、VisualVM 或类似工具)检查 JVM 上被阻塞线程的数量,并使用线程转储检查被阻塞线程的停止位置。