java - JPA 插入 + Oracle 序列和带有 H2 的 Junit
问题描述
我有一个使用 JPA 和 Oracle 作为 DB 的 Spring MvC 项目,具有以下实体:
@Entity
@Table(name = "AUTORISATION_TAURU")
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
@EqualsAndHashCode(of = {"autorisationTaurusId"})
public class AutorisationTauru implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TAURU")
@SequenceGenerator(sequenceName = "SEQ_AUTORISATION_TAURUS", allocationSize = 1, name = "SEQ_TAURU")
@Column(name = "AUTORISATION_TAURUS_ID")
private Long autorisationTaurusId;
..
}
在我的 xml 配置文件中,我有这个;
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:~/test2;DB_CLOSE_DELAY=-1;MODE=Oracle;INIT=RUNSCRIPT FROM 'classpath:create_db.sql'\;
RUNSCRIPT FROM 'classpath:create_db2.sql'\;
RUNSCRIPT FROM 'classpath:create_func.sql'" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="H2" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="bonanza-entities" />
<property name="packagesToScan">
<array>
<value>com.bonanza.model</value>
</array>
</property>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="eclipselink.target-database">org.eclipse.persistence.platform.database.OraclePlatform</prop>
</props>
</property>
</bean>
我已经使用 AUTO_INCREMENT 选项创建了我正在执行 INSERT 的表:
CREATE TABLE IF NOT EXISTS AUTORISATION_TAURU
(
AUTORISATION_TAURUS_ID NUMBER ,
但是当我运行本地测试时,我收到了这个错误:
Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLSyntaxErrorException:
Syntax error in SQL statement "SELECT SEQ_AUTORISATION_TAURUS.NEXTVAL FROM[*] DUAL"; expected "identifier"; SQL statement:
SELECT SEQ_AUTORISATION_TAURUS.NEXTVAL FROM DUAL [42001-200]
Error Code: 42001
Call: SELECT SEQ_AUTORISATION_TAURUS.NEXTVAL FROM DUAL
Query: ValueReadQuery(sql="SELECT SEQ_AUTORISATION_TAURUS.NEXTVAL FROM DUAL")
如果我添加续集创作:
CREATE SEQUENCE SEQ_AUTORISATION_TAURUS
MINVALUE 1 MAXVALUE 9223372036854775807
START WITH 1 INCREMENT BY 1 CACHE 8 NOCYCLE;
运行测试时出现此错误:
... 43 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is javax.persistence.PersistenceException: Exception [EclipseLink-28019] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Deployment of PersistenceUnit [bonanza-entities] failed. Close all factories for this PersistenceUnit.
Internal Exception: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLSyntaxErrorException: Sequence "SEQ_AUTORISATION_TAURUS" already exists; SQL statement:
解决方案
您的设置的问题可能在于您的测试创建了多次 Spring 应用程序上下文。
每次运行新测试时,它都会重新创建dataSource
bean,此外,它还会尝试启动 H2 数据库初始化脚本。
在正常情况下,第一次测试将创建 H2 数据库文件夹和相关的东西,下一次将重用它。
根据这些脚本的内容,它在大多数情况下都会起作用,但并不总是像您的情况一样。
为避免该问题,您有多种选择。
一方面,在这种特定情况下,您可以IF NOT EXISTS
在序列创建代码中包含该子句:
CREATE SEQUENCE IF NOT EXISTS SEQ_AUTORISATION_TAURUS...
在一般情况下,您可以修改您的脚本以考虑到这一事实,如果不存在,则创建不同的 H2 元素,或者首先创建DROP
您CREATE
需要的每个元素。
另一方面,Spring Test 也为您提供了类似目的的@DirtiesContext
注解:
指示
ApplicationContext
与测试关联的测试注释是脏的,因此应该关闭并从上下文缓存中删除。
和:
@DirtiesContext
可以用作同一类或类层次结构中的类级别和方法级别注释。在这种情况下,ApplicationContext
将在任何此类注释方法之前或之后以及当前测试类之前或之后将 标记为脏,具体取决于配置的methodMode()
andclassMode()
。
如您所见,您只需要使用此注释来注释您的类或测试方法,Spring 将相应地重新创建上下文:
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
请注意,这种方法会对您的测试性能产生影响,因为需要重新创建 Spring 应用程序上下文,但另一方面,它会根据您的初始化脚本始终为您提供干净且确定性的数据库状态.
推荐阅读
- angular - 具有范围验证的角度日期范围选择器
- python - 如何在 Python 中将 sinc 低通滤波器应用于 RGB 图像?
- regex - Postgresql 子字符串正则表达式
- html - 如何在开发工具中检查 ::-webkit-datetime-edit
- spartacus-storefront - 如何访问类别页面中的当前 CategoryData?
- postgresql - 将来自 web 的 tsv 文件中的数据插入到 postgres 表中
- django - 如何在 django admin 中使用 multselect 字段进行过滤
- swift - UIStackView 内的项目溢出
- php - 将匹配词提取到 JSON 文件
- javascript - 激活和停用 Marketing Assets Dynamics 365