附录 B:R2DBC 操作符速查

R2DBC 与 Spring Data R2DBC 操作符速查:ConnectionFactory 创建、Statement 参数绑定与执行、Result map 与 rowsUpdated、DatabaseClient SQL 构建、以及 Repository 派生查询命名规则对照表。

R2DBC SPI 速查

创建连接

ConnectionFactory factory = new PostgresqlConnectionFactory(
    PostgresqlConnectionConfiguration.builder()
        .host("localhost").port(5432).database("eventd")
        .username("eventd").password("eventd")
        .build()
);

Mono<Connection> conn = Mono.from(factory.create());

拿到 Connection 只是开始,必须保证归还。推荐直接用 usingWhen 把「获取 → 使用 → 关闭」包成一条链:

Mono<User> user = Mono.usingWhen(
    Mono.from(factory.create()),
    c -> Mono.from(c.createStatement("SELECT * FROM users WHERE id = $1")
            .bind("$1", 1)
            .execute())
        .flatMap(result -> Mono.from(result.map((row, meta) ->
            new User(row.get("id", Long.class), row.get("name", String.class))))),
    c -> Mono.from(c.close())  // close() 返回 Publisher,必须订阅
);

查询

Mono.from(conn.createStatement("SELECT * FROM users WHERE id = $1")
    .bind("$1", 1)
    .execute())
    .flatMapMany(result -> result.map((row, meta) ->
        new User(row.get("id", Long.class), row.get("name", String.class))
    ));

插入 + 返回生成键

Mono.from(conn.createStatement("INSERT INTO users (name) VALUES ($1)")
    .bind("$1", "alice")
    .returnGeneratedValues("id")
    .execute())
    .flatMapMany(result -> result.map((row, meta) -> row.get("id", Long.class)));

批量

Statement stmt = conn.createStatement("INSERT INTO logs (level, msg) VALUES ($1, $2)");
stmt.bind("$1", "INFO").bind("$2", "ok").add();
stmt.bind("$1", "WARN").bind("$2", "low").add();
// 批量时每个 add() 产生一个 Result:用 Flux.from,Mono.from 只取第一个
Flux.from(stmt.execute()).flatMap(Result::getRowsUpdated);

关闭连接

Mono.from(conn.close());            // 惰性:返回 Publisher,尚未执行
Mono.from(conn.close()).subscribe(); // 真正关闭
Mono.from(conn.close()).block();     // 在测试/启动脚本里同步等待关闭

Connection.close() 返回 Publisher<Void>,直接写 conn.close(); 什么都不会发生,连接也不会归还连接池。

DatabaseClient 速查

// 单行查询
db.sql("SELECT * FROM users WHERE id = :id")
    .bind("id", 1)
    .map((row, meta) -> new User(...))
    .one();

// 多行查询
db.sql("SELECT * FROM users WHERE status = :status")
    .bind("status", "ACTIVE")
    .map((row, meta) -> new User(...))
    .all();

// 更新
db.sql("UPDATE users SET status = :status WHERE id = :id")
    .bind("status", "INACTIVE")
    .bind("id", 1)
    .fetch()
    .rowsUpdated();

// 存在性检查
db.sql("SELECT 1 FROM users WHERE id = :id")
    .bind("id", 1)
    .fetch()
    .first()
    .hasElement();

Repository 派生查询规则

关键字示例生成的 WHERE
AndfindByNameAndStatusname = ? AND status = ?
OrfindByNameOrEmailname = ? OR email = ?
Is, EqualsfindByNameIsname = ?
LikefindByNameLikename LIKE ?(通配符由调用方提供)
StartingWithfindByNameStartingWithname LIKE ?,参数值自动变成 prefix%
EndingWithfindByNameEndingWithname LIKE ?,参数值自动变成 %suffix
ContainingfindByNameContainingname LIKE ?,参数值自动变成 %value%
GreaterThanfindByAgeGreaterThanage > ?
BetweenfindByAgeBetweenage BETWEEN ? AND ?
InfindByStatusInstatus IN (?, ?, ...)
NotInfindByStatusNotInstatus NOT IN (?, ?, ...)
OrderByfindByStatusOrderByNameDescORDER BY name DESC
TruefindByActiveTrueactive = true
FalsefindByActiveFalseactive = false
IgnoreCasefindByNameIgnoreCaseUPPER(name) = UPPER(?)

Like 和 Containing/StartingWith/EndingWith 的区别:前者把值原样交给 SQL,% 要自己拼;后者由 Spring Data 自动加通配符。混用会出现 %% 或通配符丢失。

小结

本附录汇总 R2DBC SPI 和 Spring Data R2DBC 的常用操作。原始 SPI 用于调试和性能优化,DatabaseClient 用于复杂查询,Repository 用于 CRUD 和简单条件查询。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java」更多文章

  1. 15.3 全书总结与学习路径回顾
  2. 15.2 响应式流处理的演进趋势
  3. 15.1 引擎选型指南