mariadb/mysql R2DBC(CRUD)方式接入spring boot (二)

依然是start.spring.io创建,大致的依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-r2dbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		<dependency>
			<groupId>org.mariadb</groupId>
			<artifactId>r2dbc-mariadb</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.mariadb.jdbc</groupId>
			<artifactId>mariadb-java-client</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>

使用kotlin需要再加入:

		<dependency>
			<groupId>com.fasterxml.jackson.module</groupId>
			<artifactId>jackson-module-kotlin</artifactId>
		</dependency>
		<dependency>
			<groupId>io.projectreactor.kotlin</groupId>
			<artifactId>reactor-kotlin-extensions</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-reflect</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-stdlib-jdk8</artifactId>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlinx</groupId>
			<artifactId>kotlinx-coroutines-reactor</artifactId>
		</dependency>

配置数据库和(一介绍的一样)

spring:
  r2dbc:
    username: user
    password: psw
    url: r2dbc:mariadb://hostname:port/dataname

新建一个实体类例如:

import org.springframework.data.annotation.Id

class Customer(val firstName: String, val lastName: String) {
    @Id
    var id: Long? = null

    override fun toString() = String.format(
        "Customer[id=%d, firstName='%s', lastName='%s']", 
        id, firstName, lastName
    )
    
}

新建一个初始化bean来执行初始化sql(此bean同样适用于方式一)

	@Bean
    fun initializer(): ConnectionFactoryInitializer {
        val initializer = ConnectionFactoryInitializer()
        initializer.setConnectionFactory(connectionFactory)
        initializer.setDatabasePopulator(ResourceDatabasePopulator(ClassPathResource("schema.sql")))
        return initializer
    }

schema.sql 如下:

DROP TABLE IF EXISTS customer;
CREATE TABLE IF NOT EXISTS customer (id SERIAL PRIMARY KEY, first_name VARCHAR(255), last_name VARCHAR(255)) CHARSET=utf8;

创建实体类仓库:

import org.springframework.data.repository.reactive.ReactiveCrudRepository

interface CustomerRepository : ReactiveCrudRepository<Customer?, Long?>

在RestController中使用:

class cot (
    val customerRepository: CustomerRepository
) { ... }

以上java的写法就结束了
spring.io官网Going Reactive with Spring, Coroutines and Kotlin Flow有提到kotlin支持,推荐kotlin仓库的写法是这样的:

import org.springframework.data.repository.kotlin.CoroutineCrudRepository

interface CustomerRepository2: CoroutineCrudRepository<Customer,Long> {
}

根据说明这是一个协程仓库,经过测试crud速度跟spring mvc下速度接近,但是可以利用协程并发。
以下是对这些仓库方法的测试。
测试数据库为远程腾讯云上自己假设的,mariadb数据库(有网络延迟),测试全部为单插入500条数据(用save而不是saveAll)
测试1接口,使用响应式方式调ReactiveCrudRepository接口(时间约10-300毫秒,第一次最慢,几次后加快)非常快

@GetMapping("insert1")
    fun insert1(): Long {
        val time = System.currentTimeMillis()
        Flux.range(1,500).flatMap { customerRepository.save(Customer("abc","bcd")) }.subscribe()
        return System.currentTimeMillis() - time
    }

测试2, 使用响应式方式调ReactiveCrudRepository接口(时间约70-300毫秒)非常快接近第一种

@GetMapping("insert2")
    fun insert2(): Long {
        val time = System.currentTimeMillis()
        (1..500).forEach { _ -> customerRepository.save(Customer("abc","bcd")).subscribe() }
        return System.currentTimeMillis() - time
    }

测试3 ,使用CoroutineCrudRepository接口循环(时间快接近20000毫秒,不忍直视)

@GetMapping("insert3")
    suspend fun insert3() = measureTimeMillis {
        (1 ..500).forEach{ _ -> customerRepository2.save(Customer("abc","bcd"))}
    }

契而不舍,官网推荐用法怎么可能,不停的修改接口代码(时间1100-1400毫秒,最大努力了)

@GetMapping("insert5")
    suspend fun insert5() = measureTimeMillis {
        foo().buffer().collect { it.await() }
    }

    suspend fun foo() = flow {
        coroutineScope {
            for (i in 1..500) {
                emit(async { customerRepository2.save(Customer("abc", "bcd")) })
            }
        }
    }

可能还是kotlin flow用的不够好,有更好的可以留言。
对比响应式的插入速度,如果现在开发新项目还选择jdbc的,实在对不起金主啊!
推荐大家使用

ReactiveCrudRepository

方式CRUD

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值