更新1(向下滚动)
设置如下:
我们的应用程序数据库由两个不同的用户构建和使用:
*SCHEMA-有权创建和授予对表和
*APP-被SCHEMA授予以上表使用权限(INSERT、UPDATE、DELETE、SELECT)的用户。
这使我们能够锁定任何模式更改,直到需要为止,因此不会通过应用程序用户发生深刻的更改。
我正在使用一个包含这两个用户的实时Oracle数据库运行集成测试。在类本身上,我使用@SqlConfig(dataSource = "schemaDataSource", transactionManager = "transactionManagerSchema")
。
在测试方法中,我放置了两个失败的@Sql
,因为在SqlScriptsTestExecutionListener
类中,事务没有管理相同的数据源(因此下面有错误消息)。
我尝试过手动设置数据源到事务管理器,如下面的配置类所示,然而一些未知的进程似乎每次都覆盖它。(我最好的猜测是通过@DataJpaTest
注解,但我不知道11个自动配置中的哪一个,正如你所看到的,我已经禁用了一对夫妇,没有效果)。
- 测试类别 *:
@RunWith(SpringRunner.class)
@DataJpaTest(excludeAutoConfiguration = {TestDatabaseAutoConfiguration.class, DataSourceAutoConfiguration.class})
@FlywayTest
@SqlConfig(dataSource = TestDataSourceConfig.SCHEMA_DATA_SOURCE, transactionManager = "transactionManagerSchema")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {TestDataSourceConfig.class, TestFlywayConfig.class})
@EntityScan(basePackageClasses = BaseEnum.class)
public class NotificationTypeEnumTest {
@Autowired
private EntityManager em;
@Test
@Sql(statements = {"INSERT INTO MYAPP_ENUM (ENUM_ID, \"TYPE\", \"VALUE\") VALUES (MYAPP_ENUM_ID_SEQ.nextval, '" + NotificationTypeEnum.DTYPE + "', 'foo')"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(statements = {"DELETE FROM MYAPP_ENUM"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void canFetchNotificationTypeEnum() throws Exception {
TypedQuery<NotificationTypeEnum> query = em.createQuery("select a from NotificationTypeEnum a", NotificationTypeEnum.class);
NotificationTypeEnum result = query.getSingleResult();
assertEquals("foo", result.getValue());
assertEquals(NotificationTypeEnum.DTYPE, result.getConfigType());
}
}
- 数据源和TM配置 *:
@Slf4j @Configuration @EnableTransactionManagement
public class TestDataSourceConfig {
public static final String SCHEMA_DATA_SOURCE = "schemaDataSource";
public static final String SCHEMA_TRANSACTION_MANAGER = "schemaTransactionManager";
/*Main Datasource and supporting beans*/
@Bean @Primary @ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() { return new DriverManagerDataSource(); }
@Bean @Primary @Autowired
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { return new JpaTransactionManager(emf); }
@Bean(name = SCHEMA_DATA_SOURCE) @ConfigurationProperties(prefix = "myapp.datasource.test_schema")
public DataSource schemaDataSource() { return new DriverManagerDataSource(); }
@Bean(name = SCHEMA_TRANSACTION_MANAGER) @Autowired
public PlatformTransactionManager transactionManagerSchema(@Qualifier(SCHEMA_DATA_SOURCE) DataSource dataSource) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource);
return jpaTransactionManager;
}
}
我无法在标题中找到的完整错误是:
java.lang.IllegalStateException: Failed to execute SQL scripts for test context
...
SOME LONG STACK TRACE
...
the configured DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource] (named 'schemaDataSource') is not the one associated with transaction manager [org.springframework.orm.jpa.JpaTransactionManager] (named 'transactionManagerSchema').
当有一个DataSource
时,Spring自动配置模型似乎工作正常,但是,一旦有2个或更多,假设就会崩溃,程序员需要手动填充所需配置中的突然(大量)间隙。
我是否错过了一些关于DataSources和TransactionManagers的基本知识?
更新1
经过一些调试我发现在检索TransactionManager以与@Sql
脚本注解一起使用时,在我创建的bean上调用了afterPropertiesSet()
方法。(即JpaTransactionManager.entityManagerFactory
)根据其配置的EntityManagerFactoryInfo.getDataSource()
设置数据源。EntityManagerFactory
本身是由于调用JpaTransactionManager.setBeanFactory
方法而被设置的(因为它实现了BeanFactoryAware
)。
下面是Spring代码:
// JpaTransactionManager.java
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (getEntityManagerFactory() == null) {
if (!(beanFactory instanceof ListableBeanFactory)) {
throw new IllegalStateException("Cannot retrieve EntityManagerFactory by persistence unit name " +
"in a non-listable BeanFactory: " + beanFactory);
}
ListableBeanFactory lbf = (ListableBeanFactory) beanFactory;
setEntityManagerFactory(EntityManagerFactoryUtils.findEntityManagerFactory(lbf, getPersistenceUnitName()));
}
}
然后,我尝试创建自己的EntityManagerFactory bean,试图将其注入到我创建的事务管理器中,但这似乎打开了Hibernate特定的类,我希望在JPA
级别保持抽象。
2条答案
按热度按时间tquggr8v1#
最后,一个仅JPA的解决方案!
解决方案是使用提供的spring
EntityManagerFactoryBuilder
组件控制EntityManagerFactoryBeans
的创建,并使用@PersistenceContext
注解将EntityManager注入测试。下面是两个数据源的配置。与应用程序相关的DataSource bean在其定义中都有
@Primary
,以消除任何@Autowired
依赖项的歧义。除了通过@DataJpaTest
类完成的自动休眠配置之外,不需要Hibernate特定的类。EntityManagerFactoryBuilder
-我不喜欢工厂工厂,但这个工厂工厂很好地帮助我创建了EntityManagerFactory的正确实现,而不依赖于任何hibernate特定的类。可以注入@Autowired
。构建器bean本身通过HibernateJpaAutoConfiguration
类(扩展JpaBaseConfiguration
)(由@DataJpaTest
导入)进行配置。JpaProperties
-用于在生成的entitymanagerfactories中维护application.properties
配置。通过此配置类上面的@EnableConfigurationProperties(JpaProperties.class)
注解启用。@PersistenceContext(unitName = "...")
-我可以用这个注解在我的测试类中注入正确的EntityManager
。hmmo2u0o2#
年份#2023-
org.springframework. Boot :spring-boot-starter-test:jar:2.7.10:test
在我的应用程序中,已经有配置文件,但同样没有加载,导致上述错误。发现HikariConfig正在加载属性为value ie。并试图加载数据库驱动程序为${primary.datasources.abc.driverClassName} ie
配置文件
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef =“preAlertEntityManagerFactory”,
transactionManagerRef =“preAlertTransactionManager”,
basePackages =“com.abc.repository”
)
@SuppressWarnings(value = {“unused”})
public class Uncategorized {
@Value(“${主要.数据源.abc.驱动程序类名}”)
private String textName;
@Value(“${primary.datasources.abc.url}”)
public String url;
....
Junit测试文件****为上下文初始化所做的更改(如下所示)
@ActiveProfiles(profiles = {“integration”})// application-integration.yml文件
@Sql(scripts = {“/dml/prealert.sql”})
@SpringBootTest
@DirtiesContext**@ContextConfiguration(
初始化器= {ConfigDataApplicationContextInitializer.class})**
class ABC class{
……
}