Spring Data R2DBC
英文全部为Reactive Relational Database Connectivity
反应式关系数据库连接
这个项目并不是一个完成的项目,目前处于孵化阶段。所以支持的数据库较少。
支持的数据库
-
Postgres(io.r2dbc:r2dbc-postgresql)
-
H2(io.r2dbc:r2dbc-h2)
-
Microsoft SQL Server(io.r2dbc:r2dbc-mssql)
并不支持主流的MySql等关系型数据库
不管用拿一个都要使用相关依赖。
一些主要的类
- ConnectionFactory
重写这个类,定义连接 - DatabaseClient
通过DatabaseClient执行sql操作,调用里面的方法
• execute().sql(SQL) 自己手动输入SQL语句
• select( )/insert( ) 输入表名查找
• inTransaction(db -> {}) 如果有事务的要求,把后面的操作包裹起来 - R2dbcExceptionTranslato 处理异常r
• SqlErrorCodeR2dbcExceptionTranslator
具体使用如下:
/**
* @Author: 13679
* @CreateTime: 2019-12-02 21:39
*/
@Slf4j
@SpringBootApplication
public class R2dbcDemoTest extends AbstractR2dbcConfiguration implements ApplicationRunner {
@Autowired
private DatabaseClient client; //注入一个数据库客户端
public static void main(String[] args) {
SpringApplication.run(R2dbcDemoTest.class,args);
}
@Bean
public ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(
H2ConnectionConfiguration.builder() //使用h2的连接工厂创建一个连接,inMemory为内存数据库的名字,
.inMemory("testdb")
.username("sa")
.build()
);
}
@Bean //@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
public R2dbcCustomConversions r2dbcCustomConversions(){ //覆盖掉r2dbcCustomConversions,本来里面list是空的
Dialect dialect = getDialect(connectionFactory());
CustomConversions.StoreConversions storeConversions=
CustomConversions.StoreConversions.of(dialect.getSimpleTypeHolder());
return new R2dbcCustomConversions(storeConversions,
Arrays.asList(new MoneyReadConverter(),new MoneyWriteConverter()));
}
@Override
public void run(ApplicationArguments args) throws Exception {
CountDownLatch count = new CountDownLatch(2);
client.execute()
.sql("select * from t_coffee")
.as(Coffee.class)
//将查出来的数据转化为coffee对象
.fetch()
//将整个结果集取出
.first()
//取出第一个
.doFinally(c->count.countDown())
.subscribeOn(Schedulers.elastic())
.subscribe(c->log.info("Fetch execute {}",c));
client.select()
.from("t_coffee")
.orderBy(Sort.by(Sort.Direction.DESC,"id"))
//根据id 降序排序
.page(PageRequest.of(0,3))
.as(Coffee.class)
.fetch()
.all()
.doFinally(c->count.countDown())
.subscribeOn(Schedulers.elastic())
.subscribe(c -> log.info("Fetch execute {}", c));
log.info("After Starting ...");
count.await();
}
}
结果如下:
R2DBC Repository 支持
一些主要的类
- @EnableR2dbcRepositories
开启Repositories支持 - ReactiveCrudRepository<T(实例), ID(类型)>
• @Table / @Id
Table :使用的哪个表
Id:哪个属性是它的id
• 其中的方法返回都是 Mono 或者 Flux
• 自定义查询需要自己写 @Query
具体代码:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table("t_coffee") //使用的表
public class Coffee {
@Id
private Long id;
private String name;
private Money price;
private Date createTime;
private Date updateTime;
}
public interface CoffeeRepository extends ReactiveCrudRepository<Coffee, Long> {
@Query("select * from t_coffee where name = $1")
Flux<Coffee> findByName(String name);
}
@SpringBootApplication
@Slf4j
@EnableR2dbcRepositories
public class R2dbcRepositoryDemoApplication extends AbstractR2dbcConfiguration
implements ApplicationRunner {
@Autowired
private CoffeeRepository repository;
public static void main(String[] args) {
SpringApplication.run(R2dbcRepositoryDemoApplication.class, args);
}
@Bean
public ConnectionFactory connectionFactory() {
return new H2ConnectionFactory(
H2ConnectionConfiguration.builder()
.inMemory("testdb")
.username("sa")
.build());
}
@Bean
public R2dbcCustomConversions r2dbcCustomConversions() {
Dialect dialect = getDialect(connectionFactory());
CustomConversions.StoreConversions storeConversions =
CustomConversions.StoreConversions.of(dialect.getSimpleTypeHolder());
return new R2dbcCustomConversions(storeConversions,
Arrays.asList(new MoneyReadConverter(), new MoneyWriteConverter()));
}
@Override
public void run(ApplicationArguments args) throws Exception {
CountDownLatch cdl = new CountDownLatch(2);
repository.findAllById(Flux.just(1L, 2L))
//使用默认的findAllById 输入两个id 1和2
.map(c -> c.getName() + "-" + c.getPrice().toString())
//使用map输出咖啡
.doFinally(s -> cdl.countDown())
.subscribe(c -> log.info("Find {}", c));
repository.findByName("mocha")
.doFinally(s -> cdl.countDown())
.subscribe(c -> log.info("Find {}", c));
cdl.await();
}
}
converter层是一样
结果如下: