[英]Why does H2 database tells me my table does not exist for some tests only
我有一个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:
从Employer雇主0_中选择雇主0_.id作为ID1_2_0_,雇主0_。名称作为名称2_2_0_其中雇主0_.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。
这似乎是由于初始化数据库时关闭连接导致数据库关闭。
因此,当您执行单独的查询SQL时,由于数据库已关闭,您将无法找到表:找不到Table "EMPLOYER" not found
如果要保持数据库开放供使用,可以尝试向数据库URL @Value(“ $ {spring.datasource.url}”)添加参数。
DB_CLOSE_DELAY=-1
像:
jdbc:h2:tcp://localhost/xxxxx:xxxxxx;DB_CLOSE_DELAY=-1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.