r2dbc介绍及动态数据源实现⽅式
⼀、基本概念:
传统情况Java 使⽤ JDBC 来操作关系型数据库,⽽ JDBC 是阻塞的、同步的,即使使⽤线程池进⾏改善也是有限的。基于此,Spring官⽅(Pivotal)提出了R2DBC(Reactive Relational Database Connectivity)。R2DBC是⼀项API规范计划,它声明了⼀个反应式API,该⽅法将由数据库⼚商实现以访问其关系数据库。
⽬前实现了R2DBC的数据库驱动有: 、 。
使⽤maven添加两个依赖:r2dbc 接⼝、数据库驱动实现。
例如:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-r2dbc</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.github.jasync-sql</groupId>
<artifactId>jasync-r2dbc-mysql</artifactId>
<version>1.1.4</version>
</dependency>
注:Maven Central到⽬前为⽌还没有R2DBC⼯件,因此我们还需要在项⽬中添加⼏个Spring的存储库。
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
⼆、直接使⽤r2bdc
使⽤r2dbc访问关系型数据库的核⼼是创建⼀个io.r2dbc.spi.ConnectionFactory接⼝的实例(通常使⽤单例)。如:
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import org.apachemons.logging.Log;
import org.apachemons.logging.LogFactory;
st.StepVerifier;
import org.springframework.R2dbcEntityTemplate;
public class R2dbcApp {
private static final Log log = Log(R2dbcApp.class);
public static void main(String[] args) {
ConnectionFactory connectionFactory = ("r2dbc:h2:mem:///test?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");    R2dbcEntityTemplate template = new R2dbcEntityTemplate(connectionFactory);
"(id VARCHAR(255) PRIMARY KEY," +
"name VARCHAR(255)," +
"age INT)")
.fetch()
.rowsUpdated()
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
template.insert(Person.class)
.using(new Person("joe", "Joe", 34))
.as(StepVerifier::create)spring ioc注解
.expectNextCount(1)
.verifyComplete();
template.select(Person.class)
.first()
.
doOnNext(it -> log.info(it))
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
}
}
也可通过spring的⽅式创建连接⼯⼚。
@Configuration
public class ApplicationConfiguration extends AbstractR2dbcConfiguration {
@Override
@Bean
public ConnectionFactory connectionFactory() {
return …
}
}
ConnectionFactory创建完成后,可通过它得到访问数据库的操作类:R2dbcEntityTemplate(提供了⾯向实体的数据库访问操作)。
三、使⽤spring repository ⽀持
需要使⽤注解@EnableR2dbcRepositories开启功能。如下
@Configuration
@EnableR2dbcRepositories
class ApplicationConfig extends AbstractR2dbcConfiguration {
@Override
public ConnectionFactory connectionFactory() {
return …
}
}
再创建相应的repository接⼝
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> {
// additional custom query methods go here
}
然后就可以使⽤repository特性来进⾏数据库操作了,例如:
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class PersonRepositoryTests {
@Autowired
PersonRepository repository;
@Test
void readsAllEntitiesCorrectly() {
repository.findAll()
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
}
@Test
void readsEntitiesByNameCorrectly() {
repository.findByFirstname("Hello World")
.as(StepVerifier::create)
.expectNextCount(1)
.verifyComplete();
}
}
四、r2dbc动态数据源的实现⽅案
r2dbc提供了org.tion.lookup.AbstractRoutingConnectionFactory抽象类,并需要我们⾃⼰实
现protected abstract Mono<Object> determineCurrentLookupKey();⽅法以达到动态切换数据源的⽬的。
项⽬中实现动态数据源的流程如下:
1、spring ioc启动时,通过jdbc⽅式加载中⼼库数据源,由中⼼库查询对话库配置信息及相应公司id与serverKey对应关系(serverKey与数据源⼀对⼀,公司id与serverKey多对⼀)
2、通过对话库配置信息创建多个ConnectionFactory,得到 Map<String, ConnectionFactory> connectionFactoryMap。此hash的key为serverKey,value为⼀个可⽤的ConnectionFactory
3、调⽤AbstractRoutingConnectionFactory的public void setTargetConnectionFactories(Map<?, ?> targetConnectionFactories)⽅法设置值连接⼯⼚集合
4、调⽤AbstractRoutingConnectionFactory的public void setDefaultTargetConnectionFactory(Object defaultTargetConnectionFactory)设置默认连接⼯⼚
5、重写protected abstract Mono<Object> determineCurrentLookupKey()⽅法。从**Context**中获取公司id对应的**serverKey**
注:此处需要使⽤到reactor的⾼级特性:Context(具有与ThreadLocal类似的功能),它是⼀个键值对的数据结构。它作⽤于⼀个Flux或⼀个Mono上,⽽不是应⽤于⼀个线程(Thread)。
并且它使⽤Subscription的传播机制来让⾃⼰对每⼀个操作符都可见(从最后⼀个subscribe沿链向上)。因此需要在调⽤链最后或尽可能后的位置 (调⽤subscribe()前 )创建Context并将其绑定到Flux或Mono上。
6、将我们⾃⼰实现的AbstractRoutingConnectionFactory的⼦类通过@Bean注⼊ioc容器
7、在进⾏数据库操作时将公司id绑定到Flux或Mono中的Context上。
参考⽂档:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。