java - Arquillian 和 Flyway 使用不同版本的 H2 内存
问题描述
我正在尝试创建一个 JPA-helper,它最终将变成一个 jar 并用于其他项目。我想向这个项目添加集成测试,所以我添加了一个TestEntity
和类(这些是指架构中的TestService
一个简单TEST
表)。DB
目标是使用H2创建内存数据库,使用Arquillian在容器中运行测试,并使用Flyway创建/填充测试数据库。Flyway 是由一个类的监听器触发的。@ApplicationScoped
但是,每当我触发集成测试时,测试似乎都可以正常工作,直到count(*)
调用查询。此时,Hibernate 抱怨架构(刚刚在 Flyway 中创建)不存在:Schema 'DB' does not exist
有很多日志,但亮点看起来是这样的:
- 启动了一个测试 Glassfish 服务器
- 休眠开始
- 它还没有抱怨任何事情
- 如果
hibernate.hbm2ddl.auto
设置为validate
,则抱怨在 Flyway 中创建的表不存在(Schema-validation: missing table [DB.TEST]
)
- Flyway 执行数据迁移
- 它说两个脚本都成功执行
- 测试代码开始运行
- 代码失败
Schema 'DB' does not exist
我认为我需要做的
我认为 Flyway 和 EntityManager 正在与数据库的不同实例通信。Flyway 所做的更改不会以 EntityManager 可以看到的方式保存。
- 确保
EntityManager
和Flyway
正在与同一个数据库通信。- 名称相同(请参阅
persistence.xml
、EntityManagerFactory
和FlywayDataLoader
),我尝试添加/删除各种MODE
值但没有任何效果。
- 名称相同(请参阅
- 强制 Flyway 代码在 Hibernate 代码之前执行
- 在测试开始之前强制休眠刷新它的模式
我试过的
- 将语法错误放入 Flyway 迁移代码会导致测试由于 SQL 错误而失败。
- 如果您将重复语句放入 SQL 代码中(例如:再次创建表或模式),也会发生同样的情况。
- 我尝试通过 JDBC 连接字符串中的启动脚本触发 Flyway
- IE:
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:create.sql'
- 我知道脚本触发了(因为添加错误会导致测试失败),但它仍然没有解决
Schema 'DB' does not exist
问题。
- IE:
- 各种口味的
hibernate.hbm2ddl.auto
none
:Schema 'DB' does not exist
validate
:Schema-validation: missing table [DB.TEST]
update
,create-drop
: 表已创建,但 Flyway 中的数据缺失
- 将 Flyway 代码放入
EntityManagerFactory.create()
- 将 Flyway 代码放入Integrator 类并参考
- 更改 Flyway/persistence.xml 连接以使用数据库文件而不是内存(例如:)
jdbc:h2:~/test-db
。- 这会在
C:\Users\<me>
名为test-db.mv
. 该文件显示 Flyway 与其交互的证据,但 EntityManager 仍会生成Schema 'DB' does not exist
错误。 - 我也设置
hibernate.hbm2ddl.auto
为create
,然后在我的整个硬盘驱动器中搜索第二个实例test-db.mv
,但找不到。
- 这会在
什么行不通
- Arquillian 坚持
- 看起来很棒,但我在公司网络上,他们还没有批准
- 春天-*
- 这个项目不使用 Spring 任何东西
日志和代码
执行日志
// various "server startup" logs
// ...
// misc hibernate logs
Apr 15, 2020 9:40:39 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation
INFO: HHH000204: Processing PersistenceUnitInfo [
name: TestDS
...]
// ...
Loading Flyway Data
8 [main] INFO org.flywaydb.core.internal.util.VersionPrinter - Flyway Community Edition 5.0.7 by Boxfuse
246 [main] INFO org.flywaydb.core.internal.database.DatabaseFactory - Database: jdbc:h2:mem:test (H2 1.4)
354 [main] INFO org.flywaydb.core.internal.command.DbValidate - Successfully validated 2 migrations (execution time 00:00.028s)
377 [main] INFO org.flywaydb.core.internal.schemahistory.JdbcTableSchemaHistory - Creating Schema History table: "PUBLIC"."flyway_schema_history"
413 [main] INFO org.flywaydb.core.internal.command.DbMigrate - Current version of schema "PUBLIC": << Empty Schema >>
415 [main] INFO org.flywaydb.core.internal.command.DbMigrate - Migrating schema "PUBLIC" to version 1 - CreateDatabase
436 [main] INFO org.flywaydb.core.internal.command.DbMigrate - Migrating schema "PUBLIC" to version 2 - AddTestClasses
449 [main] INFO org.flywaydb.core.internal.command.DbMigrate - Successfully applied 2 migrations to schema "PUBLIC" (execution time 00:00.078s)
Apr 15, 2020 9:40:44 AM com.sun.enterprise.web.WebApplication start
INFO: Loading application [test] at [/test]
Apr 15, 2020 9:40:45 AM org.glassfish.deployment.admin.DeployCommand execute
INFO: test was successfully deployed in 7,649 milliseconds.
Apr 15, 2020 9:40:45 AM org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateService
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate:
select
count(testobject0_.id) as col_0_0_
from
DB.TEST testobject0_
where
1=1
Apr 15, 2020 9:40:45 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 30000, SQLState: 42Y07
Apr 15, 2020 9:40:45 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Schema 'DB' does not exist
// stack trace
/ ...
集成测试代码
@RunWith(Arquillian.class)
public class ProviderTest {
@Deployment
public static JavaArchive createDeployment() {
JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
.addClasses(
TestObject.class,
TestService.class,
QueryValuesProviderImpl.class,
CriteriaQueryProviderFactory.class,
EntityManagerFactory.class
)
.addClass(FlywayDataLoader.class)
.addAsResource("META-INF/persistence.xml")
.addAsManifestResource(new ByteArrayAsset(new byte[0]), ArchivePaths.create("beans.xml"));
System.out.println(jar.toString(true));
return jar;
}
@Inject
private TestService testService;
@Test
public void testGetTestResource() {
List<TestObject> data = testService.getTestObjects(new QueryValues());
assertNotNull(data);
assertEquals(2, data.size());
}
}
飞路 Java 脚本
@ApplicationScoped
public class FlywayDataLoader {
private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
private static boolean initialized = false;
public static void setup(
@Observes @Initialized(ApplicationScoped.class) final Object event
) {
if (!initialized) {
System.out.println("Loading Flyway Data");
Flyway flyway = new Flyway();
flyway.setDataSource(JDBC_URL, "sa", "");
flyway.setBaselineOnMigrate(true);
flyway.migrate();
initialized = true;
}
}
}
飞路 SQL 脚本
这分为两个文件(一个用于创建模式/表,第二个用于插入实际数据)。这些文件位于文件夹中,并/resources/db.migration/
分别命名为和。V1__CreateDatabase.sql
V2__AddTestClasses.sql
CREATE SCHEMA DB;
create table DB.TEST
(
ID INT auto_increment
constraint PK_REQUEST_AUDIT
primary key,
FN VARCHAR2(256 char) default NULL not null,
LN VARCHAR2(256 char) default NULL not null,
BD TIMESTAMP default SYSDATE not null
)
;
insert into DB.TEST (FN, LN, BD) VALUES ('Alice', 'Zyl', PARSEDATETIME('1985-03-13','yyyy-MM-dd','en'));
insert into DB.TEST (FN, LN, BD) VALUES ('Bart', 'Young', PARSEDATETIME('1988-03-25','yyyy-MM-dd','en'));
实体管理器
此处使用的unitName
与 中使用的持久性单元名称匹配persistence.xml
。此处使用的 JDBC 连接字符串与 Flyway Java 脚本中使用的相同。
public class EntityManagerFactory {
@PersistenceUnit(unitName="TestDS")
private javax.persistence.EntityManagerFactory emFactory;
@Produces
@Default
@RequestScoped
public EntityManager create() {
return emFactory.createEntityManager();
}
public void dispose(@Disposes @Default EntityManager em){
if(em.isOpen()){
em.close();
}
}
}
持久性.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="TestDS" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>myproject.beans.TestObject</class>
<properties>
<!-- Configuring JDBC properties -->
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<!-- Hibernate properties -->
<property name="hibernate.ddl-auto" value="none" />
<property name="hibernate.connection.user" value="sa" />
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
不起眼的 DAO 类?
@RequestScoped
public class TestService {
@Inject
private EntityManager em;
@Inject
private CriteriaQueryProviderFactory criteriaQueryProviderFactory;
public List<TestObject> getTestObjects(QueryValues queryValues) {
CriteriaQueryProvider<TestObject> criteriaQueryProvider = criteriaQueryProviderFactory.getFactory();
CriteriaQuery<TestObject> criteriaQuery = criteriaQueryProvider.buildModifiedQuery(queryValues, TestObject.class);
TypedQuery<TestObject> typedQuery = criteriaQueryProvider.addSecondaryModifiers(criteriaQuery, queryValues, TestObject.class);
TypedQuery<Long> countQuery = criteriaQueryProvider.buildCountQuery(queryValues, TestObject.class);
System.out.println(String.format("There are %d objects total!", countQuery.getSingleResult()));
return typedQuery.getResultList();
}
}
解决方案
我发现将 Flyway 与 Hibernate 集成的最佳方法是使用以下实现
org.hibernate.integrator.spi.Integrator
:https ://docs.jboss.org/hibernate/orm/5.4/javadocs/org/hibernate/integrator/spi/Integrator.html 。该接口有两个方法,integrate
和disintegrate
. 如果您将运行 Flyway 的代码放入integrate
您的实现方法中,一切都应该可以正常工作。Hibernateorg.hibernate.integrator.spi.Integrator
从 Java 标准 API 加载服务加载器机制的实现,因此您必须创建一个META-INF/services/org.hibernate.integrator.spi.Integrator
包含实现的完全限定类名的文件。
最好的
延斯
推荐阅读
- c# - 为什么只输出法师?
- php - PHP:当继承的类调用父函数时记录或跟踪
- c# - 在我的应用程序服务中抛出休息异常与向我的控制器添加额外的逻辑以确定我是否需要回复 404
- excel - 在中间名前插入空格
- python - 从 django 视图调用 Python CLI 程序并异步显示结果?
- javascript - UTF-8 的 Javascript 解析器?
- vba - 是否可以确定两个对象是否都实现了在编译时未指定的公共接口?
- sql - sql case 条件作为另一个表中的 SELECT
- javascript - 单击按钮时用新文本替换文本
- aws-lambda - 通过 lambda 从 Cognito 用户池中获取用户属性