spring data r2dbc
15 December 2019
spring data r2dbc를 이용해 mysql을 연동하는 예제를 진행해보도록 하겠습니다.
먼저 아래와 같이 dependencies를 추가해주도록 합니다.
현재 예제의 spring boot 버전은 2.2.2.RELEASE 입니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
compile group: 'org.springframework.data', name: 'spring-data-r2dbc', version: '1.0.0.RELEASE'
compile group: 'io.r2dbc', name: 'r2dbc-pool', version: '0.8.0.RELEASE'
compile group: 'com.github.jasync-sql', name: 'jasync-r2dbc-mysql', version: '1.0.12'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
그리고 아래와 같이 mysql database 설정을 추가해줍니다.
package org.shashaka.io.demo;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryOptions;
import io.r2dbc.spi.Option;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.dialect.MySqlDialect;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import java.time.Duration;
import static io.r2dbc.spi.ConnectionFactoryOptions.*;
@Configuration
@EnableR2dbcRepositories
public class DatabaseConfig {
@Bean
public ReactiveDataAccessStrategy reactiveDataAccessStrategy() {
return new DefaultReactiveDataAccessStrategy(new MySqlDialect());
}
@Bean
public ConnectionFactory connectionFactory() {
return ConnectionFactories.get(ConnectionFactoryOptions.builder()
.option(DRIVER, "pool")
.option(PROTOCOL, "mysql")
.option(HOST, "[mysql_server_host]")
.option(PORT, 3306)
.option(USER, "[mysql_user]")
.option(PASSWORD, "[mysql_password]")
.option(DATABASE, "demo")
.option(CONNECT_TIMEOUT, Duration.ofSeconds(2L))
.option(Option.valueOf("acquireRetry"), 3)
.option(Option.valueOf("initialSize"), 10)
.option(Option.valueOf("maxSize"), 100)
.option(Option.valueOf("validationQuery"), "SELECT 1")
.option(Option.valueOf("validationDepth"), "REMOTE")
.build());
}
@Bean
public DatabaseClient databaseClient(ConnectionFactory connectionFactory) {
return DatabaseClient.builder()
.connectionFactory(connectionFactory)
.build();
}
}
mysql에 생성되어있는 table과 entity를 맵핑하기 위해 아래처럼 table class를 작성해줍니다.
package org.shashaka.io.demo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import java.sql.Timestamp;
@Table("MyGuests")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyGuest {
@Id
@Column
private Integer id;
@Column
private String firstname;
@Column
private String lastname;
@Column
private String email;
@Column
private Timestamp reg_date;
}
이후, spring-data-jpa와 비슷한 형식으로 repository를 추가해주도록 합니다.
package org.shashaka.io.demo;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DemoRepository extends ReactiveCrudRepository {
}
restController를 만들어 준 후, API를 호출해주면 정상적으로 동작하는 것을 확인할 수 있습니다.
package org.shashaka.io.demo;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@AllArgsConstructor
public class DemoController {
private final DemoRepository demoRepository;
@GetMapping("/demo")
public Flux demo() {
return demoRepository.findAll();
}
@PostMapping("/demo")
@ResponseStatus(HttpStatus.OK)
public Mono addGuest(@RequestBody MyGuest myGuest) {
return demoRepository.save(myGuest);
}
}
$ http.exe :8080/demo <<< '{"firstname":"dsf","lastname":"fedwfefw"}'
{"id":6,"firstname":"dsf","lastname":"fedwfefw","email":null,"reg_date":null}
$ http :8080/demo
HTTP/1.1 200
Connection: keep-alive
Content-Type: application/json
Date: Sun, 15 Dec 2019 06:00:58 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
[
{
"email": null,
"firstname": "dsf",
"id": 6,
"lastname": "fedwfefw",
"reg_date": "2019-12-14T21:00:54.000+0000"
}
]