【问题标题】:Why does H2 database tells me my table does not exist for some tests only为什么 H2 数据库告诉我我的表不存在仅用于某些测试
【发布时间】:2018-05-22 02:15:28
【问题描述】:

我有一个 Spring JPA 存储库,我正在尝试使用 H2 内存数据库进行测试。一些测试通过,而另一些则没有。问题是 H2 告诉我我的表不存在(这很奇怪,因为通过的测试也使用了同一张表)。

这是我的数据库配置:

@Configuration
@Import({BaseConfiguration.class, DatabaseProperties.class})
@EnableJpaRepositories(basePackages = DatabaseConfiguration.REPOSITORIES_PACKAGE)
public class DatabaseConfiguration {

    /*
     * Constants
     */
    public static final String MODEL_PACKAGE = "be.dupirefr.examples.spring.batch.simple.model";
    public static final String REPOSITORIES_PACKAGE = "be.dupirefr.examples.spring.batch.simple.repositories";

    /*
     * Beans
     */
    @Bean
    public DataSource dataSource(DatabaseProperties properties) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(properties.url);
        dataSource.setUsername(properties.username);
        dataSource.setPassword(properties.password);
        dataSource.setDriverClassName(properties.driverClassName);

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPackagesToScan(MODEL_PACKAGE);
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        return entityManagerFactoryBean;
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

}

上一个配置类中使用的属性存储在一个映射到以下配置类的database.properties文件中:

@Configuration
@PropertySource("classpath:be/dupirefr/examples/spring/batch/simple/config/database/database.properties")
public class DatabaseProperties {

    /*
     * Fields
     */
    @Value("${spring.datasource.url}")
    public String url;

    @Value("${spring.datasource.username}")
    public String username;

    @Value("${spring.datasource.password}")
    public String password;

    @Value("${spring.datasource.driver-class-name}")
    public String driverClassName;

}

此文件使用 database.properties 文件中的属性:

spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=admin
spring.datasource.password=admin
spring.datasource.driver-class-name=org.h2.Driver

这里是 Employer 类及其存储库测试类:

雇主:

@Entity
public class Employer {

    /*
     * Fields
     */
    @Id
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(mappedBy = "employer")
    private List<Employee> employees;

    /*
     * Constructors
     */
    private Employer() {}

    public Employer(Long id, String name) {
        this.id = id;
        this.name = name;

        this.employees = new ArrayList<>();
    }

    /*
     * Getters
     */
    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public List<Employee> getEmployees() {
        return employees;
    }

    /*
     * Methods
     */
    //...

}

EmployerRepositoryIT:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DatabaseConfiguration.class)
@Transactional
public class EmployerRepositoryIT {

    /*
     * Constants
     */
    public static final Employer GOOGLE = new Employer(1L, "Google");
    public static final Employer MICROSOFT = new Employer(2L, "Microsoft");
    public static final Employer APPLE = new Employer(3L, "Apple");

    /*
     * Fields
     */
    @Autowired
    private EmployerRepository repository;

    @Autowired
    private EntityManager entityManager;

    /*
     * Setups
     */
    @Before
    public void setUp() {
        entityManager.persist(GOOGLE);
        entityManager.persist(MICROSOFT);
    }

    /*
     * Tests
     */
    @Test
    public void findById_Exists() {
        assertEquals(GOOGLE, repository.findById(GOOGLE.getId()).get());
        assertEquals(MICROSOFT, repository.findById(MICROSOFT.getId()).get());
    }

    @Test
    public void findById_NotExists() {
        assertFalse(repository.findById(Long.MAX_VALUE).isPresent());
    }

    @Test
    public void findAll() {
        assertEquals(Arrays.asList(GOOGLE, MICROSOFT), repository.findAll());
    }

    @Test
    public void save() {
        repository.save(APPLE);
        assertEquals(APPLE, entityManager.find(Employer.class, APPLE.getId()));
    }

    @Test
    public void delete() {
        repository.delete(MICROSOFT);
        assertNull(entityManager.find(Employer.class, MICROSOFT.getId()));
    }

}

由于我只是测试 JpaRepository 方法,因此我省去了 EmployerRepository 接口,这里没有附加值。

在上面显示的测试中,只有 findById_Exists 和 delete 有效。对于其他人,我收到以下错误:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select employer0_.id as id1_2_0_, employer0_.name as name2_2_0_ from Employer employer0_ where employer0_.id=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement

这似乎是由以下原因引起的:

org.h2.jdbc.JdbcSQLException: Table "EMPLOYER" not found; SQL statement:

从雇主employer0_ 中选择employer0_.id 作为id1_2_0_,employer0_.name 作为name2_2_0_,其中employer0_.id=? [42102-187]

我还为我的数据库 url 尝试了以下操作:

你知道问题可能是什么吗?

jdbc:h2:mem:test;DB_CLOSE_DELAY=-1

jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE

但它们都不起作用。

编辑: 我想通了一些东西。失败的测试是那些实际到达数据库的测试。其他的只是在 EntityManager 的缓存中执行。所以看来我的问题在于 H2 数据库配置或类似的东西。我会检查一下,但如果有人有想法会受到欢迎。

编辑 2: 很好,添加 DB_CLOSE_DELAY=-1 就可以了。我只是忘了告诉 Hibernate 生成 DDL。

【问题讨论】:

  • 您使用的是什么版本的 h2?另外,您为集成测试配置的spring.datasource.url 是什么?
  • 抱歉,我应该显示我的 database.properties 文件。我将它添加到我的帖子中。这是我的数据库 url:jdbc:h2:mem:test 正如我在帖子中添加的那样,我还尝试了一些参数,例如 DB_CLOSE_DELAY=-1 或 DB_CLOSE_ON_EXIT=FALSE。但没有人成功。
  • 而我的h2版本是1.4.187
  • 还是不知道? :-P

标签: java spring jpa h2


【解决方案1】:

这似乎是由于数据库连接时关闭 被初始化,导致数据库关闭。

所以当你执行单独的查询SQL时,由于数据库已经关闭,你将无法找到Table:Table "EMPLOYER" not found

如果要保持数据库开放使用,可以尝试添加 数据库 URL 的参数 @Value("${spring.datasource.url}")

DB_CLOSE_DELAY=-1

喜欢:

jdbc:h2:tcp://localhost/xxxxx:xxxxxx;DB_CLOSE_DELAY=-1

【讨论】:

  • 我编辑了我的帖子以提供更多解释。我已经尝试过 DB_CLOSE_DELAY=-1 和 DB_CLOSE_ON_EXIT=FALSE,但它们都没有成功:-/
  • 还是不知道? :-P
  • 很好,添加 DB_CLOSE_DELAY=-1 就可以了。我只是忘了告诉 Hibernate 生成 DDL。
猜你喜欢
  • 2011-03-08
  • 1970-01-01
  • 2010-11-20
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
  • 2017-12-30
  • 2021-08-15
  • 1970-01-01
相关资源
最近更新 更多