主要原因是如下代码导致的:
1,在BaseDaoImpl中通过以下代码获取session:
@PersistenceContext
protected EntityManager entityManager;
public Session getSession() {
Session session = entityManager.unwrap(Session.class);
return entityManager.unwrap(Session.class);
}
2,但是在springboot中配置的事务管理器并不是hibernate的事务管理器,而是一个org.springframework.jdbc.datasource.DataSourceTransactionManager事务管理器,它管理的session和hibernate的session不是一个。
@Bean
@Autowired
public DataSourceTransactionManager transactionManager(@Qualifier("db2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
跟踪DruidDataSource的getConnectionInternal()方法和recycle()可以看到数据源生命周期的开始和释放的调用栈。最后发现连接泄露的原因如下图:
解决办法:
1,事务管理器用hibernate的事务管理器:
@Bean
public LocalSessionFactoryBean sessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
LocalSessionFactoryBean bean = new LocalSessionFactoryBean();
bean.setDataSource(dataSource);
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.DB2Dialect");
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.format_sql", "true");
bean.setHibernateProperties(properties);
bean.setPackagesToScan("com.wx.**.model");
return bean;
}
@Bean
public HibernateTransactionManager transactionManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
final HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
hibernateTransactionManager.setSessionFactory(sessionFactory);
return hibernateTransactionManager;
}
2,修改BaseDaoImpl中获取session的代码:
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
return sessionFactory.getCurrentSession();
}