Реактивные операции Spring Data R2DBC MySQL

Spring Boot Java

1. Введение

существуетИспользуйте R2DBC для работы с базой данных MySQLПредварительное знакомство сr2dbc-mysqlиспользование. благодаря помощиDatabaseClientдействоватьMySQL, слишком начальный и низкоуровневый, не способствующий развитию. Воспользуйтесь преимуществами сегодняшнего дняSpring Data R2DBCпоказыватьАбстракция репозитория данных Spring (репозиторий данных Spring)СтильR2DBCоперации с базой данных.

Пожалуйста, обрати внимание:В настоящее времяSpring Data R2DBCХотя было переработано несколько официальных версий, она все еще находится в зачаточном состоянии, и ее недостаточно для использования в производстве. Однако будущее многообещающе и заслуживает изучения.

2. Spring Data R2DBC

Spring Data R2DBCпредоставляется на основеR2DBCДрайверы популярных реактивных реляционных баз данныхRepositoryАннотация. Но это не структура ORM, вы можете думать о ней как об уровне абстракции для доступа к базе данных илиR2DBCклиентская программа. это не обеспечиваетORMФреймворк имеет множество функций, таких как кэширование и отложенная загрузка, но он абстрагирует абстрактные отношения сопоставления между базами данных и объектами и является легким и простым в использовании.

2.1 Соответствие версий

Толстый брат подвел итогиSpring Data R2DBCиSpring FrameworkВерсия соответствует:

Spring Data R2DBC Spring Framework
1.0.0.RELEASE 5.2.2.RELEASE
1.1.0.RELEASE 5.2.6.RELEASE
1.1.1.RELEASE 5.2.7.RELEASE
1.1.2.RELEASE 5.2.8.RELEASE

Обязательно обращайте внимание на соответствие версий, чтобы избежать несовместимости.

3. Основные зависимости

Я не цитировал в прошлый раз.R2DBCПул соединений, на этот раз я попробую его использовать. Основные зависимости следующие, здесь я также интегрировалSpring Webflux:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<!--  r2dbc 连接池 -->
<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-pool</artifactId>
</dependency>
<!--r2dbc mysql 库-->
<dependency>
    <groupId>dev.miku</groupId>
    <artifactId>r2dbc-mysql</artifactId>
</dependency>
<!--自动配置需要引入的一个嵌入式数据库类型对象-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<!-- 反应式web框架 webflux-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Здесь я используюSpring Boot 2.3.2.RELEASE.

4. Конфигурация

В прошлый раз мы использовалиJavaConfigконфигурация стиля, нужно толькоSpring IoCввестиConnectionFactory. На этот раз я попробуюapplication.yamlСредняя конфигурацияR2DBCнеобходимые параметры.

spring:
  r2dbc:
    url: r2dbcs:mysql://127.0.0.1:3306/r2dbc
    username: root
    password: 123456

ВышеупомянутоеR2DBCосновная конфигурация. Особо следует отметить, чтоspring.r2dbc.urlФормат файла отличается в зависимости от различных методов записи базы данных.Очень важно видеть определение драйвера. Пул соединений может использовать здесь конфигурацию по умолчанию, нет необходимости явно определять ее.

5. Напишите бизнес-код

Следующим шагом является написание бизнес-кода. Здесь я также пытаюсь использоватьDatabaseClientвыполнитьDDLзаявление созданоclient_userСтол чувствует себя очень хорошо.

@Autowired
DatabaseClient databaseClient;

@Test
void doDDL() {

    List<String> ddl = Collections.unmodifiableList(Arrays.asList("drop table if exists client_user;", "create table client_user(user_id varchar(64) not null primary key,nick_name varchar(32),phone_number varchar(16),gender tinyint default 0) charset = utf8mb4;"));
    ddl.forEach(sql -> databaseClient.execute(sql)
            .fetch()
            .rowsUpdated()
            .as(StepVerifier::create)
            .expectNextCount(1)
            .verifyComplete());
}

5.1 Объявление сущностей базы данных

Знаком сSpring Data JPAОдноклассники должны быть хорошо знакомы с ним.

/**
 *  the client user type
 *
 * @author felord.cn
 */
@Data
@Table
public class ClientUser implements Serializable {
    private static final long serialVersionUID = -558043294043707772L;
    @Id
    private String userId;
    private String nickName;
    private String phoneNumber;
    private Integer gender;
}

5.2 Объявление интерфейса CRUD

в вышеуказанном классе сущностей@TableАннотации говорят, когда наш рабочий интерфейс наследуетReactiveCrudRepository<T, ID>илиReactiveSortingRepository<T, ID>Когда вам нужно использовать класс сущности@TableОбратите внимание, что это также рекомендуемое использование.

public interface ReactiveClientUserSortingRepository extends ReactiveSortingRepository<ClientUser,String> {
    
}

Конечно, класс сущности не использует@TableПри аннотировании тегов мы также можем наследоватьR2dbcRepository<T, ID>интерфейс. потомReactiveClientUserSortingRepositoryБудут предоставлены некоторые методы манипулирования базой данных.

Repository提供的一些默认操作数据库的方法

потомSpring Data JPAКак писать, здесь почти как писать, но некоторые функции еще не поддерживаются, такие как упомянутая выше подкачка и стратегия первичного ключа.

похожийPagingAndSortingRepository<T,ID>Интерфейс функции реактивной разбивки на страницы еще не реализован и будет интегрирован в будущей версии.

5.3 Практическая эксплуатация

Далее мы проходимR2DBCФактическая операцияMySQLбаза данных. Согласно нашей традиционной логике, мы написали следующую новую логику:

ClientUser clientUser = new ClientUser();

clientUser.setGender(2);
clientUser.setNickName("r2dbc");
clientUser.setPhoneNumber("9527");
clientUser.setUserId("snowflake");

Mono<ClientUser> save = reactiveClientUserSortingRepository.save(clientUser);

В результате никакие данные не были записаны в базу данных. В это время, потому чтоr2dbc-mysqlЕго нельзя использовать напрямую, но он может быть реализован только клиентом и делегирован клиенту для работы.

Это тожеR2DBCПринцип разработки R2DBC заключается в том, чтобы свести к минимуму плоскость SPI, цель состоит в том, чтобы исключить различные части между базами данных и сделать всю базу данных полностью реактивной и противодействующей. Он в основном используется в качестве драйвера SPI, используемого клиентскими библиотеками, и не предназначен для непосредственного использования в коде приложения.

Итак, здесь мы можем использоватьreactor-testТестовая библиотека для ее выполнения, чтобы прочитать:

reactiveClientUserSortingRepository.save(clientUser)
        .log()
        .as(StepVerifier::create)
        .expectNextCount(1)
        .verifyComplete();

Но все равно не удается выполнить успешно, подскажитеupdate table [client_user]. Row with Id [snowflake] does not exist, то есть ожидается, что будет добавлено обновление, но фактическое выполнение является обновлением, потому что база данных не может найти первичный ключ, посколькуsnowflakeЗапись неверна. Почему здесь обновление?

В это время, поскольку класс сущности будет определять, заполняется ли первичный ключ при добавлении нового значения, если он не заполняется, он считается новыми данными, и выполняется настоящая новая операция обновления. толстый братSpring Data R2DBCПообщавшись с командой проекта, я не получил дружественного решения, но нашел способ, так что оставим здесь дыру.

Так как вы добавляете данные? Мы можем использовать только@Queryпримечание, чтобы написатьSQLнаписал:

@Modifying
@Query("insert into client_user (user_id,nick_name,phone_number,gender) values (:userId,:nickName,:phoneNumber,:gender)")
Mono<Integer> addClientUser(String userId, String nickName, String phoneNumber, Integer gender);

при добавлении@ModifyingПосле этого возвращаемое значение можно изменить сMono<ClientUser>,Mono<Boolean>илиMono<Integer>любой выбор.

reactiveClientUserSortingRepository
        .addClientUser("snowflake",
                "r2dbc",
                "132****155",
                0)
        .as(StepVerifier::create)
        .expectNextCount(1)
        .verifyComplete();

r2dbc 写入成功log

Это доказало успешную запись данных.

5.4 Использование с Webflux

Но как это применить на практике? Единственное, о чем я могу думать на данный момент, это объединить реактивный фреймворкSpring Webflux, какSpring Data JPAСотрудничатьSpring MVCТакой же.

мы пишемWebfluxинтерфейс:

@RestController
@RequestMapping("/user")
public class ReactiveClientUserController {

    @Autowired
    private ReactiveClientUserSortingRepository reactiveClientUserSortingRepository;


    /**
     * 这里为了检验默认api 就不分层了
     *
     * @param userId the user id
     * @return the mono
     */
    @GetMapping("/{userId}")
    public Mono<ClientUser> findUserById(@PathVariable String userId) {
        return reactiveClientUserSortingRepository.findById(userId);
    }

}

webflux 通过r2dbc查询mysql数据库

5.5 Некоторые ссылки на тестовые данные

При низком уровне параллелизмаSpring MVC + JDBCЛучше всего работает, но при высоком уровне параллелизмаWebFlux + R2DBCИспользуйте наименьшее количество ресурсов на каждый обработанный запрос.

并发下的CPU占用

В условиях высокого параллелизмаSpring MVC + JDBCВремя отклика начинает падать. Очевидно,R2DBCОбеспечивает лучшие времена отклика при более высоком параллелизме.Spring WebFluxтакже, чем использованиеSpring MVCПодобная реализация лучше.

吞吐量对比

6. Резюме

Да, сегодняSpring Data R2DBCДальнейшая демонстрация, я считаю, что вы можете чему-то научиться из нее. так какR2DBCВсе еще относительно новый, есть еще некоторые вещи, которые нуждаются в доработке и дополнениях. В настоящее время сообщество очень активно и развивается очень быстро. Что ж, сегодняшняя статья здесь, оригиналу не так просто уделить больше внимания:Кодекс сельского хозяйстваЕсли вы считаете эту статью полезной, ставьте лайк, делайте репост и читайте снова.

关注公众号:Felordcn获取更多资讯

Личный блог: https://felord.cn