반응형

R2DBC

R2DBC란?

  • R2DBC는 Reactive Relational Database Connectivity의 약어
  • Reactive(Non-Blocking Asyncronous)하게 RDBMS에 접근하여 데이터를 활용할 수 있도록 해주는 라이브러리를 말한다.

init table

DROP TABLE IF EXISTS User;
CREATE TABLE User
(
    userSeq BIGINT AUTO_INCREMENT,
    name    VARCHAR(255),
    PRIMARY KEY (userSeq)
);

INSERT INTO User (name) VALUES ('john');
INSERT INTO User (name) VALUES ('tom');
INSERT INTO User (name) VALUES ('jane');
INSERT INTO User (name) VALUES ('tyler');

gradle.build

dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    runtimeOnly 'dev.miku:r2dbc-mysql'
}

application.properties

logging.level.org.springframework.r2dbc=DEBUG

spring.r2dbc.url=r2dbc:pool:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
spring.r2dbc.username=ubuntu
spring.r2dbc.password=123456

User

@AllArgsConstructor
@NoArgsConstructor
@Data
@Table("User")
public class User {
    @Id
    @Column("userSeq")
    private Long userSeq;
    @Column("name")
    private String name;
}

UserRepository

public interface UserRepository extends ReactiveCrudRepository<User, Long> {
}

UserController

@RequiredArgsConstructor
@RestController
public class UserController {
    private final UserRepository userRepository;

    @GetMapping("/api/users")
    public Flux<User> getUsers() {
        return Flux.mergeSequential(
            userRepository.findById(1L),
            userRepository.findById(2L),
            userRepository.findById(3L),
            userRepository.findById(4L)
        );
    }
}

MongoDB

gradle.build

dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
}

application.properties

spring.data.mongodb.uri=mongodb://root:123456@localhost:27017/dev?authSource=admin

User

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document("user")
public class User {
    @Id
    private String id;
    private String name;
}

UserRepository

public interface UserRepository extends ReactiveMongoRepository<User, String> {
}

UserController

@RequiredArgsConstructor
@RestController
public class UserController {
    private final ReactiveMongoTemplate mongoTemplate;
    private final UserRepository userRepository;

    @GetMapping("/api/v1/users")
    public Flux<User> getUsersV1() {
        return Flux.mergeSequential(
            mongoTemplate.findById("1", User.class),
            mongoTemplate.findById("2", User.class),
            mongoTemplate.findById("3", User.class),
            mongoTemplate.findById("4", User.class)
        );
    }

    @GetMapping("/api/v2/users")
    public Flux<User> getUsersV2() {
        return Flux.mergeSequential(
            userRepository.findById("1"),
            userRepository.findById("2"),
            userRepository.findById("3"),
            userRepository.findById("4")
        );
    }
}

Redis

gradle.build

dependencies {
    ...
    implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
}

application.properties

spring.redis.host=localhost
spring.redis.port=6379

MessageController

@RequiredArgsConstructor
@RestController
public class MessageController {
    private final ReactiveStringRedisTemplate redisTemplate;

    @GetMapping("/api/messages/{id}")
    public Mono<String> getMessages(@PathVariable String id) {
        return redisTemplate.opsForValue().get("message:" + id);
    }
}

Redisson Distributed Lock

gradle.build

dependencies {
    ...
    implementation 'org.redisson:redisson-spring-boot-starter:3.16.0'
}

application.properties

spring.redis.host=localhost
spring.redis.port=6379

UserController

@RequiredArgsConstructor
@RestController
public class UserController {
    private final UserRepository userRepository;
    private final RedissonReactiveClient redissonReactiveClient;

    @GetMapping("/api/users/{name}")
    public Mono<String> addUser(@PathVariable String name) {
        RLockReactive lock = redissonReactiveClient.getLock("username:" + name);
        long threadId = Thread.currentThread().getId();

        Mono<String> statusMono = userRepository.findByName(name).map(user -> "exists")
            .switchIfEmpty(userRepository.save(new User(null, name)).map(user -> "success"));

        return lock.tryLock(5, 5, TimeUnit.SECONDS, threadId)
            .flatMap(s -> statusMono)
            .doFinally(signalType -> lock.unlock(threadId).subscribe());
    }
}
반응형

'Development > WebFlux' 카테고리의 다른 글

[WebFlux] Stream API  (0) 2021.07.17
[WebFlux] WebClient  (0) 2021.07.17
[WebFlux] Test  (0) 2021.07.17
[WebFlux] Controller  (0) 2021.07.17
[WebFlux] Introduction  (0) 2021.07.13

+ Recent posts