当使用R2DBC(Reactive Relational Database Connectivity)时,您可以使用Converter将数据库中的数据类型转换为Java对象,以便更方便地处理数据。同时,您可以使用DatabaseClient执行基于响应式流的数据库操作。以下是R2DBC Converter和DatabaseClient的具体使用案例:
继承自此webFlux基础下的R2DBC操作
R2DBC Converter简单使用案例:
假设您正在使用Spring Boot和R2DBC与数据库交互,并且有一个名为User
的实体类,其中包含id
(UUID类型)和name
(String类型)属性。您可以使用Converter将数据库中的数据类型转换为User
对象。
首先,创建一个实现Converter
接口的自定义转换器:
import io.r2dbc.spi.Row;import io.r2dbc.spi.RowMetadata;import org.springframework.core.convert.converter.Converter;import org.springframework.data.convert.ReadingConverter;@ReadingConverterpublic class UserConverter implements Converter<Row, User> {@Overridepublic User convert(Row row) {UUID id = row.get("id", UUID.class);String name = row.get("name", String.class);return new User(id, name);}}
添加一个配置类,将UserConverter 配置进Bean中
@EnableR2dbcRepositories //开启 R2dbc 仓库功能;jpa@Configurationpublic class R2DbcConfiguration {@Bean //替换容器中原来的@ConditionalOnMissingBeanpublic R2dbcCustomConversions conversions(){//把我们的转换器加入进去; 效果新增了我们的 Converterreturn R2dbcCustomConversions.of(MySqlDialect.INSTANCE,new UserConverter());}}
然后,在您的数据库配置类中注册自定义转换器:
import org.springframework.context.annotation.Configuration;import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;import org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtension;import org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtensionSupport;@Configuration@EnableR2dbcRepositoriespublic class DatabaseConfig extends AbstractR2dbcConfiguration {@Overridepublic R2dbcCustomConversions r2dbcCustomConversions() {return new R2dbcCustomConversions(Collections.singletonList(new UserConverter()));}}
现在,您可以在使用R2dbcRepository
的地方查询User
对象,并且查询结果会自动转换为User
对象。
DatabaseClient使用案例:
DatabaseClient是Spring Data R2DBC中用于执行数据库操作的核心类。以下是一个简单的使用案例,演示如何使用DatabaseClient执行查询和插入操作。
首先,确保您的项目中已经添加了相关的依赖,包括spring-boot-starter-data-r2dbc
。
接下来,创建一个包含DatabaseClient的服务类:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.r2dbc.core.DatabaseClient;import org.springframework.stereotype.Service;import reactor.core.publisher.Flux;import reactor.core.publisher.Mono;@Servicepublic class UserService {private final DatabaseClient databaseClient;@Autowiredpublic UserService(DatabaseClient databaseClient) {this.databaseClient = databaseClient;}public Flux<User> getAllUsers() {return databaseClient.select().from("users").as(User.class).fetch().all();}public Mono<User> getUserById(UUID id) {return databaseClient.select().from("users").matching(Criteria.where("id").is(id)).as(User.class).fetch().one();}public Mono<User> createUser(User user) {return databaseClient.insert().into("users").using(user).map((row, metadata) -> user).first();}}
在上面的代码中,getAllUsers
方法使用fetch().all()
从数据库中获取所有用户。getUserById
方法使用fetch().one()
根据ID获取单个用户。createUser
方法使用insert().using(user)
将用户对象插入到数据库中,并返回插入后的用户对象。
请注意,上述代码中的User
类是根据您的实际需求自定义的。
当然!以下是更多关于R2DBC Converter和DatabaseClient的使用案例:
R2DBC Converter高级使用案例:
- 写入数据转换器:除了读取数据之外,您还可以编写转换器将Java对象转换为数据库中的数据类型。例如,假设您希望将
User
对象转换为数据库行:
import io.r2dbc.spi.Row;import io.r2dbc.spi.RowMetadata;import org.springframework.core.convert.converter.Converter;import org.springframework.data.convert.WritingConverter;@WritingConverterpublic class UserWritingConverter implements Converter<User, Row> {@Overridepublic Row convert(User user) {return DefaultRow.of(DefaultColumn.of("id", user.getId()), DefaultColumn.of("name", user.getName()));}}
- 自定义类型转换器:如果您的实体类中包含自定义类型的属性,您可以编写自定义转换器来处理这些类型。例如,假设您的
User
类中有一个Address
对象作为属性,您可以编写转换器将Address
对象转换为数据库中的字符串类型:
import io.r2dbc.spi.Row;import io.r2dbc.spi.RowMetadata;import org.springframework.core.convert.converter.Converter;import org.springframework.data.convert.WritingConverter;@WritingConverterpublic class AddressWritingConverter implements Converter<Address, String> {@Overridepublic String convert(Address address) {// Convert Address object to a string representation// For example, return address.getStreet() + ", " + address.getCity() + ", " + address.getCountry();}}
- Converter的组合使用:如果您有多个转换器,您可以将它们组合在一起以实现复杂的数据转换逻辑。例如,您可以创建一个转换器链将数据库行转换为复杂的领域对象:
import io.r2dbc.spi.Row;import io.r2dbc.spi.RowMetadata;import org.springframework.core.convert.converter.Converter;import org.springframework.data.convert.ReadingConverter;@ReadingConverterpublic class UserComplexConverter implements Converter<Row, User> {private final Converter<Row, SimpleUser> simpleUserConverter;private final Converter<Row, Address> addressConverter;public UserComplexConverter(Converter<Row, SimpleUser> simpleUserConverter, Converter<Row, Address> addressConverter) {this.simpleUserConverter = simpleUserConverter;this.addressConverter = addressConverter;}@Overridepublic User convert(Row row) {SimpleUser simpleUser = simpleUserConverter.convert(row);Address address = addressConverter.convert(row);// Combine simpleUser and address to create a User object}}
DatabaseClient高级使用案例:(可以自定义SQL)
- 执行更新操作:除了查询和插入操作之外,您还可以使用DatabaseClient执行更新和删除操作。例如,执行一个更新操作来更新用户的名称:
public Mono<Integer> updateUser(UUID id, String newName) {return databaseClient.execute("UPDATE users SET name = :name WHERE id = :id").bind("name", newName).bind("id", id).fetch().rowsUpdated();}
- 使用事务:DatabaseClient还支持事务操作。您可以使用
DatabaseClient::inTransaction
方法在事务中执行一系列数据库操作。例如,以下代码展示了在事务中插入多个用户的示例:
public Flux<User> createUsersInTransaction(List<User> users) {return databaseClient.inTransaction().execute(tx -> Flux.fromIterable(users).flatMap(user -> tx.execute("INSERT INTO users (id, name) VALUES (:id, :name)").bind("id", user.getId()).bind("name", user.getName()).fetch().rowsUpdated().thenReturn(user))).thenMany(Flux.fromIterable(users));}
在上述代码中,createUsersInTransaction
方法将用户对象列表作为输入,并在事务中将它们逐个插入数据库。事务的提交由thenMany
操作完成。
- 处理结果集:DatabaseClient的结果集可以通过
map
、flatMap
和其他操作进行进一步处理。例如,以下代码演示了如何将结果集转换为自定义对象列表:
public Flux<UserDetails> getUserDetails() {return databaseClient.select().from("users").matching(Criteria.where("age").isGreaterThan(18)).as(User.class).fetch().all().flatMap(user -> getAdditionalDetails(user.getId()).map(details -> new UserDetails(user, details)));}private Mono<AdditionalDetails> getAdditionalDetails(UUID userId) {// Perform additional query to fetch additional details based on user ID// Return Mono}
上述代码中,getUserDetails
方法从数据库中获取大于18岁的用户,并使用flatMap
操作对每个用户调用getAdditionalDetails
方法获取附加详细信息。然后,使用map
操作将用户对象和附加详细信息组合成UserDetails
对象。