Springboot 整合 r2dbc

r2dbc:
init 源码:

public class R2dbcScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {
   
   

	private final ConnectionFactory connectionFactory;

	/**
	 * Creates a new {@code R2dbcScriptDatabaseInitializer} that will initialize the
	 * database recognized by the given {@code connectionFactory} using the given
	 * {@code settings}.
	 * @param connectionFactory connectionFactory for the database
	 * @param settings initialization settings
	 */
	public R2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,
			DatabaseInitializationSettings settings) {
   
   
		super(settings);
		this.connectionFactory = connectionFactory;
	}

	@Override
	protected boolean isEmbeddedDatabase() {
   
   
		return EmbeddedDatabaseConnection.isEmbedded(this.connectionFactory);
	}

	@Override
	protected void runScripts(List<Resource> scripts, boolean continueOnError, String separator, Charset encoding) {
   
   
		ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
		populator.setContinueOnError(continueOnError);
		populator.setSeparator(separator);
		if (encoding != null) {
   
   
			populator.setSqlScriptEncoding(encoding.name());
		}
		for (Resource script : scripts) {
   
   
			populator.addScript(script);
		}
		populator.populate(this.connectionFactory).block();
	}

}
class R2dbcScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {
   
   

	@Override
	protected Set<Class<?>> getDatabaseInitializerBeanTypes() {
   
   
		return Collections.singleton(R2dbcScriptDatabaseInitializer.class);
	}

}

R2DBCScirpt 的方法:

private static final OptionsCapableWrapper optionsCapableWrapper;

	static {
   
   
		if (ClassUtils.isPresent("io.r2dbc.pool.ConnectionPool", ConnectionFactoryBuilder.class.getClassLoader())) {
   
   
			optionsCapableWrapper = new PoolingAwareOptionsCapableWrapper();
		}
		else {
   
   
			optionsCapableWrapper = new OptionsCapableWrapper();
		}
	}

	private static final String COLON = ":";

	private final Builder optionsBuilder;

	private ConnectionFactoryBuilder(Builder optionsBuilder) {
   
   
		this.optionsBuilder = optionsBuilder;
	}

	/**
	 * Initialize a new {@link ConnectionFactoryBuilder} based on the specified R2DBC url.
	 * @param url the url to use
	 * @return a new builder initialized with the options exposed in the specified url
	 * @see EmbeddedDatabaseConnection#getUrl(String)
	 */
	public static ConnectionFactoryBuilder withUrl(String url) {
   
   
		Assert.hasText(url, () -> "Url must not be null");
		return withOptions(ConnectionFactoryOptions.parse(url).mutate());
	}

	/**
	 * Initialize a new {@link ConnectionFactoryBuilder} based on the specified
	 * {@link Builder options}.
	 * @param options the options to use to initialize the builder
	 * @return a new builder initialized with the settings defined in the given
	 * {@link Builder options}
	 */
	public static ConnectionFactoryBuilder withOptions(Builder options) {
   
   
		return new ConnectionFactoryBuilder(options);
	}

	/**
	 * Initialize a new {@link ConnectionFactoryBuilder} derived from the options of the
	 * specified {@code connectionFactory}.
	 * @param connectionFactory the connection factory whose options are to be used to
	 * initialize the builder
	 * @return a new builder initialized with the options from the connection factory
	 * @since 2.5.1
	 */
	public static ConnectionFactoryBuilder derivedFrom(ConnectionFactory connectionFactory) {
   
   
		ConnectionFactoryOptions options = extractOptionsIfPossible(connectionFactory);
		if (options == null) {
   
   
			throw new IllegalArgumentException(
					"ConnectionFactoryOptions could not be extracted from " + connectionFactory);
		}
		return withOptions(options.mutate());
	}

	private static ConnectionFactoryOptions extractOptionsIfPossible(ConnectionFactory connectionFactory) {
   
   
		OptionsCapableConnectionFactory optionsCapable = OptionsCapableConnectionFactory.unwrapFrom(connectionFactory);
		if (optionsCapable != null) {
   
   
			return optionsCapable.getOptions();
		}
		return null;
	}

	/**
	 * Configure additional options.
	 * @param options a {@link Consumer} to customize the options
	 * @return this for method chaining
	 */
	public ConnectionFactoryBuilder configure(Consumer<Builder> options) {
   
   
		options.accept(this.optionsBuilder);
		return this;
	}

	/**
	 * Configure the {@linkplain ConnectionFactoryOptions#USER username}.
	 * @param username the connection factory username
	 * @return this for method chaining
	 */
	publ
<think> 嗯,用户想了解R2DBC是什么,我需要根据提供的引用材料给出清晰解释。先看文献线索:引用[1]指出R2DBC是JDBC的反应式版本,引用[4]强调它解决了传统JDBC的阻塞问题,引用[3]提到它是为SQL数据库设计的响应式API规范。 用户可能正在学习响应式编程,或是面临数据库性能瓶颈的开发人员。需要突出核心价值——异步非阻塞特性,这点在引用[2]的"云原生潜力"和引用[4]的"同步阻塞痛点"里都有印证。要注意对比传统JDBC,比如引用[4]明确说JDBC用线程池改善有限。 技术定义部分准备用三个层次展开:规范本质(引用[3]的SPI描述)、与JDBC关系(引用[1]的"升级版"说法)、异步特性(引用[4]的线程模型对比)。场景适配性也很重要,引用[2]提到的微服务架构需要重点说明。 实现原理要简单带过,重点在响应式流(背压机制是个好例子)。Spring整合部分根据引用[1][3],DatabaseClient和映射功能都需要提及。最后必须包含早期阶段的局限性提示,引用[3]的"仍处早期"是关键依据。 相关问题设计要从认知逻辑出发:先问技术对比(JDBC),再深入原理(线程模型),最后落地应用(SpringBoot整合)。用户可能是实践导向型,所以优化方案和适用场景的问题要保留。 </think> 根据引用资料,以下是关于 **R2DBC(Reactive Relational Database Connectivity)** 的核心介绍: --- ### **R2DBC 是什么?** R2DBC 是一项 **响应式关系型数据库连接规范**,可视为传统 JDBC 的升级版。其核心目标是解决 JDBC 的阻塞式模型限制,通过**非阻塞 I/O 和响应式流(Reactive Streams)** 实现数据库的异步交互[^1][^4]。 --- ### **核心特性与价值** 1. **响应式编程支持** - 基于 **Reactive Streams 规范**(Publisher-Subscriber 模型),支持背压(Backpressure)机制,避免资源过载[^2][^4]。 - 代码示例(背压控制): ```java databaseClient.sql("SELECT * FROM user") .fetch() .all() .subscribe(user -> System.out.println(user)); // 按需消费数据 ``` 2. **与传统 JDBC 的对比** | **特性** | **JDBC** | **R2DBC** | |----------------|-------------------------|-------------------------| | **线程模型** | 同步阻塞(占用线程池) | 异步非阻塞(事件驱动) | | **资源消耗** | 高并发时线程开销大 | 少量线程处理高并发请求 | | **适用场景** | 传统同步应用 | 响应式微服务、云原生 | 3. **与 Spring 生态整合** - **Spring Data R2DBC**:提供响应式 Repository、实体映射、事务管理等功能,完全适配 Spring WebFlux[^1][^3]。 ```java public interface UserRepository extends ReactiveCrudRepository<User, Long> {} ``` - **DatabaseClient**:轻量级响应式 SQL 操作接口(类似 JDBC 的 `JdbcTemplate`)[^1]。 --- ### **技术原理** - **异步驱动层**:由数据库厂商实现 R2DBC 驱动(如 PostgreSQL、MySQL),底层使用 Netty 等 NIO 框架[^4]。 - **响应式流传递**: ``` 应用层请求 → R2DBC Driver → 数据库内核 → 结果通过Publisher流式返回 ``` --- ### **适用场景** 1. **高并发低延迟系统**(如实时金融交易) 2. **云原生微服务架构**(服务间异步通信) 3. **资源受限环境**(节省线程开销) --- ### **当前局限** - **生态成熟度**:仍处于早期阶段,部分数据库驱动功能有限[^3]。 - **事务复杂性**:分布式事务支持弱于传统方案。 --- ### **相关问题** 1. R2DBC 与 JDBC 在事务处理机制上有何本质差异? 2. 如何通过 Spring Data R2DBC 实现动态数据源切换? 3. R2DBC 在哪些场景下性能反而不如 JDBC? 4. 现有主流数据库对 R2DBC 驱动的支持情况如何? > 引用来源: > [^1]: SpringBoot 整合 R2DBC 技术文档 > [^2]: R2DBC 原理与应用前景分析 > [^3]: Spring Data R2DBC 官方简介 > [^4]: R2DBC 动态数据源实现原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迅捷的软件产品制作专家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值