无法在使用WebFlux的Spring Boot中使用H2和R2DBC创建ConnectionFactory错误



我已经使用WebFlux反应模块、内存中的H2数据库和R2DBC反应驱动程序创建了一个Java Spring Boot服务。

当我运行该服务时,它会失败,并显示一个"无法创建ConnectionFactory";错误

Unable to create a ConnectionFactory for 'ConnectionFactoryOptions{options={driver=h2, protocol=mem, database=contentitem, options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE}}'. Available drivers: [ pool ]

这是一个嵌套的异常,似乎从存储库中开始,然后通过服务传播回控制器。

仔细阅读了生成的堆栈跟踪,没有发现可能存在的问题,我能找到的唯一线索是,我的CustomConnectionFactoryInitializer类中的"connectionFactory"输入参数(请参见下文(用红色波浪形突出显示("无法自动连接。有多个"connectionFactory"类型的bean"(。。。除了没有。至少只有一个明确定义的bean——我的CustomConnectionFactoryInitializer类中的那个。

知道这里发生了什么吗?

详细信息

这是一个Gradle项目,我的build.Gradle文件是:

plugins {
id 'org.springframework.boot' version '2.3.9.RELEASE'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.mycorp.service'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'io.r2dbc:r2dbc-h2'
runtimeOnly 'io.r2dbc:r2dbc-postgresql'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation 'io.projectreactor:reactor-test'
compile 'io.springfox:springfox-swagger2:3.0.0'
compile 'io.springfox:springfox-swagger-ui:3.0.0'
compile 'io.springfox:springfox-spring-webflux:3.0.0'
}
test {
useJUnitPlatform()
}

我在main/resources下添加了一个schema.sql文件,其中包含以下内容:

CREATE TABLE contentitem ( contentItemId INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, localizedName VARCHAR(100) NOT NULL);

我在同一目录中用data.sql文件填充表:

INSERT INTO contentitem (contentItemId, localizedName) VALUES (0, 'Zero');
INSERT INTO contentitem (contentItemId, localizedName) VALUES (1, 'One');
INSERT INTO contentitem (contentItemId, localizedName) VALUES (2, 'Two');

我创建了一个CustomConnectionFactoryInitializer来创建和填充数据库:

@Configuration
public class CustomConnectionFactoryInitializer {
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
initializer.setDatabasePopulator(populator);
return initializer;
}
}

我已经使用内存中的H2定义了一个"测试"配置文件,并将其在我的应用程序中激活。yml文件:

spring:
profiles:
active: test
---
spring:
profiles: dev
r2dbc:
url: r2dbc:postgresql://localhost:5432/test
username: postgres
password: postgres
logging:
level:
org.springframework.data.r2dbc: Debug
---
spring:
profiles: test
r2dbc:
url: r2dbc:h2:mem:///contentitem?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
name: sa
password:
---
spring:
profiles: prod
r2dbc:
url: r2dbc:postgresql://localhost:5432/test
username: postgres
password: postgres
logging:
level:
org.springframework.data.r2dbc: Debug

我的ContentItem模型是:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("contentitem")
public class ContentItem {
@Id
@Column("contentItemId")
private Integer contentItemId;
@Column("localizedName")
private String localizedName;
}

我的ContentItemController是:

@RestController
@RequestMapping("/contentItems")
public class ContentItemController {
@Autowired
private ContentItemService contentItemService;
@GetMapping("/{contentItemId}")
public Mono<ResponseEntity<ContentItem>> getContentItemByUserId(@PathVariable Integer contentItemId){
Mono<ContentItem> contentItem = contentItemService.getContentItemById(contentItemId);
return contentItem.map( u -> ResponseEntity.ok(u))
.defaultIfEmpty(ResponseEntity.notFound().build());
}

我的ContentItemService是:

@Service
@Slf4j
@Transactional
public class ContentItemService {
@Autowired
private ContentItemRepository contentItemRepository;
public Mono<ContentItem> getContentItemById(Integer contentItemId){
return contentItemRepository.findByContentItemId(contentItemId);
}
}

我的ContentItemRepository是:

public interface ContentItemRepository extends ReactiveCrudRepository<ContentItem,Integer> {
Mono<ContentItem> findByContentItemId(Integer contentItemId);
}

使这一切更加复杂的是,我在application.properties文件中用spring.h2.console.enabled=true启用的H2控制台在用http://localhost:8081/h2-console调用它时失败,并出现404 Not Found错误。有什么想法吗?

对我来说,在pom.xml 中缺少r2dbc postgresql

<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>

如果您使用的是Oracle数据库,则可以添加Oracle r2dbs依赖项来解决此问题。

<!-- https://mvnrepository.com/artifact/com.oracle.database.r2dbc/oracle-r2dbc -->
<dependency>
<groupId>com.oracle.database.r2dbc</groupId>
<artifactId>oracle-r2dbc</artifactId>
<version>1.0.0</version>
</dependency>

我也有类似的错误,但对我来说,根本原因是依赖关系的范围,来自:

testRuntimeOnly("com.h2database:h2")
testRuntimeOnly("io.r2dbc:r2dbc-h2")

至:

runtimeOnly("com.h2database:h2")
runtimeOnly("io.r2dbc:r2dbc-h2")

好的,所以我逐个文件地查看了我的项目,用我用作指南的repo的副本来区分每个文件。我发现了一些额外的数据库连接配置代码,我以为我已经去掉了。我一把它取下来,问题就解决了。感谢所有看过并提出建议的人。

相关内容

  • 没有找到相关文章

最新更新