Spring与测试容器不返回连接到池

问题描述

我正在尝试使用class LoggedOutNicknameBinding extends Bindings { LoggedOutNicknameBinding() { final ldp = Get.put(LocalDataProvider()); lds = Get.put(LocalDataSource(dataProvider: ldp)); repository = Get.put(UserRepository(lds)); } IUserRepository repository; LocalDataSource lds; @override void dependencies() { Get.lazyPut<LoggedOutNicknameController>( () => LoggedOutNicknameController(repository),); Get.lazyPut<UserRepository>( () => UserRepository(lds),); } } 在我的DAO上执行集成测试。 我的目标是在单独的容器中运行每个测试。为此,我添加了Testcontainers注释-我的逻辑是,如果我在每次测试中注入新的@DirtiesContext,它将有一个更新的EntityManager。是的,它实际上可以正常工作,但是,当涉及第11次测试时,我遇到一个例外,即Hikari无法创建新的连接,导致达到了连接限制。

我假设当应用执行DataSource时,当前@DirtiesContext被推离应用上下文,并且不再受Spring的管理,因此它可能会“忘记”关闭连接。 还是EntityManager有问题?

这是我的代码:

JpaUserDao.java:

Testcontainers

JpaUserDaoTest.java:

@Repository
public class JpaUserDao implements UserDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    @Override
    public long add(User user) {
        entityManager.persist(user);
        return user.getId();
    }
//other DAO methods
}

ApplicationConfigurationTest.java:


@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfigurationTest.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@Testcontainers
class JpaUserDaoTest {

    @Container
    private PostgreSQLContainer<?> postgreSqlContainer = new PostgreSQLContainer<>("postgres:13.0-alpine")
            .withDatabaseName("example")
            .withUsername("test")
            .withPassword("test");

    @Autowired
    private UserDao userDao;

    private User user;

    @BeforeEach
    void set(){
        user = new User();
      //set parameters of User
    }

    @Test
    void addShouldAddUserToDatabase() {
        long id = userDao.add(user);

        assertEquals(1,id);
    }

//other tests
}

hibernate.properties:

@ComponentScan(basePackages = "com.example")
@Configuration
@EnableTransactionManagement
public class ApplicationConfigurationTest {

    public static final String PACKAGES_TO_SCAN = "com.example.model";
    private static final String JDBC_CONFIGURATION_FILE = "src/test/resources/jdbc.properties";
    private static final String HIBERNATE_CONFIGURATION_FILE = "src/test/resources/hibernate.properties";

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPackagesToScan(PACKAGES_TO_SCAN);
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        entityManagerFactoryBean.setJpaProperties(additionalProperties());
        return entityManagerFactoryBean;
    }

    private DataSource dataSource(){
        HikariConfig hikariConfig = new HikariConfig(JDBC_CONFIGURATION_FILE);
        return new HikariDataSource(hikariConfig);
    }

    private JpaVendorAdapter jpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    private Properties additionalProperties() {
         try (InputStream input = new FileInputStream(HIBERNATE_CONFIGURATION_FILE)) {
            Properties properties = new Properties();
            properties.load(input);
             return properties;
        } catch (IOException ex) {
            throw new PropertiesLoadException();
        }
    }
}

jdbc.properties:

hibernate.show_sql=true
hibernate.hbm2ddl.auto=create
hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect

最后,异常本身:

jdbcUrl=jdbc:tc:postgresql:13.0:///example
dataSource.user=test
dataSource.password=test
dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048

解决方法

您需要将dataSource变成一个bean。由于未将其声明为bean,因此它的生命周期不受Spring的管理,因此在上下文被销毁时也不会关闭。

通常最好将bean依赖项声明为bean本身。如果那些依赖项实现AutoCloseableHikariDataSource确实如此)或依赖生命周期回调(@PreDestroy@PostConstruct)来管理其生命周期,则必须格外小心。否则,Spring不会将它们与常规对象区别对待,因此不会调用生命周期回调/自动清理。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...