Spring Boot 3 + R2DBC操作MySQL 8.0参数绑定编码异常求助
Spring Boot 3 + R2DBC MySQL 插入数据参数绑定异常解决
问题描述
使用Spring Boot 3和R2DBC开发服务,向MySQL 8.0数据库上传数据时遭遇参数绑定异常:
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Cannot encode value of type 'class io.r2dbc.spi.Parameters$InParameter'
Maven依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.koishi.web.discord</groupId> <artifactId>DiscordBotProject</artifactId> <version>0.0.1-SNAPSHOT</version> <name>DiscordBotProject</name> <description>DiscordBotProject</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.5</version> <!-- 使用当前版本 --> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.12.5</version> <!-- 使用与你的jackson版本相同的版本 --> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </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> <dependency> <groupId>com.discord4j</groupId> <artifactId>discord4j-core</artifactId> <version>3.2.5</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-r2dbc</artifactId> <version>3.1.3</version> </dependency> <dependency> <groupId>dev.miku</groupId> <artifactId>r2dbc-mysql</artifactId> <version>0.8.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
异常栈信息
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Cannot encode value of type 'class io.r2dbc.spi.Parameters$InParameter' Caused by: java.lang.IllegalArgumentException: Cannot encode value of type 'class io.r2dbc.spi.Parameters$InParameter' at dev.miku.r2dbc.mysql.codec.DefaultCodecs.encode(DefaultCodecs.java:178) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.ParametrizedStatementSupport.bind(ParametrizedStatementSupport.java:72) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.ParametrizedStatementSupport.bind(ParametrizedStatementSupport.java:39) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at org.springframework.r2dbc.core.DefaultDatabaseClient$StatementWrapper.bind(DefaultDatabaseClient.java:556) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.binding.IndexedBindMarkers$IndexedBindMarker.bind(IndexedBindMarkers.java:86) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.NamedParameterUtils$ExpandedQuery.bind(NamedParameterUtils.java:540) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.NamedParameterUtils$ExpandedQuery.bindTo(NamedParameterUtils.java:589) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$getResultFunction$5(DefaultDatabaseClient.java:378) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.ResultFunction.apply(ResultFunction.java:64) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.ResultFunction.apply(ResultFunction.java:42) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DefaultDatabaseClient.sumRowsUpdated(DefaultDatabaseClient.java:195) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DefaultDatabaseClient$DefaultGenericExecuteSpec.lambda$execute$6(DefaultDatabaseClient.java:403) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DelegateConnectionFunction.apply(DelegateConnectionFunction.java:48) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DelegateConnectionFunction.apply(DelegateConnectionFunction.java:33) ~[spring-r2dbc-6.0.11.jar:6.0.11] at org.springframework.r2dbc.core.DefaultDatabaseClient.lambda$inConnection$2(DefaultDatabaseClient.java:120) ~[spring-r2dbc-6.0.11.jar:6.0.11] at io.r2dbc.pool.MonoDiscardOnCancel$MonoDiscardOnCancelSubscriber.onNext(MonoDiscardOnCancel.java:92) ~[r2dbc-pool-1.0.1.RELEASE.jar:1.0.1.RELEASE] at io.r2dbc.pool.MonoDiscardOnCancel.subscribe(MonoDiscardOnCancel.java:50) ~[r2dbc-pool-1.0.1.RELEASE.jar:1.0.1.RELEASE] at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.5.9.jar:3.5.9] at reactor.pool.AbstractPool$Borrower.deliver(AbstractPool.java:467) ~[reactor-pool-1.0.1.jar:1.0.1] at reactor.pool.SimpleDequePool.lambda$drainLoop$9(SimpleDequePool.java:425) ~[reactor-pool-1.0.1.jar:1.0.1] at dev.miku.r2dbc.mysql.util.DiscardOnCancelSubscriber.onComplete(DiscardOnCancelSubscriber.java:104) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:340) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:103) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:187) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE] at dev.miku.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:95) ~[r2dbc-mysql-0.8.2.RELEASE.jar:0.8.2.RELEASE]
相关方法
public Mono<MessageKeywords> createKeyword(String keyword) { return databaseClient.sql("INSERT INTO message_keywords (Keyword) VALUES (:keyword)") .bind("keyword", keyword) .fetch() .rowsUpdated() .map(rowsUpdated -> new MessageKeywords(keyword)); }
数据类
@Table("message_keywords") public class MessageKeywords { @Id private Long keywordId; private String keyword; @Override public String toString() { return "MessageKeywords{" + "keywordId=" + keywordId + ", keyword='" + keyword + '\'' + '}'; } } //getters and setters are ignored
数据库表结构
CREATE TABLE message_keywords ( keywordId BIGINT PRIMARY KEY AUTO_INCREMENT, keyword JSON );
解决思路
1. 修复版本兼容性
当前使用的r2dbc-mysql:0.8.2.RELEASE适配R2DBC 0.9.x版本,而Spring Boot 3.1.3依赖R2DBC 1.0.x,版本不匹配导致参数编码逻辑冲突。
将r2dbc-mysql升级到适配R2DBC 1.0的版本,比如1.0.2.RELEASE,修改Maven依赖:
<dependency> <groupId>dev.miku</groupId> <artifactId>r2dbc-mysql</artifactId> <version>1.0.2.RELEASE</version> </dependency>
2. 显式处理JSON类型参数
数据库中keyword字段为JSON类型,但代码直接绑定String值,低版本驱动无法自动转换,可通过以下方式处理:
- 将字符串包装为JSON格式后绑定:
.bind("keyword", "\"" + keyword + "\"") - 使用
Parameters.in()指定参数类型为JSON:import io.r2dbc.spi.Parameters; import io.r2dbc.spi.R2dbcType; // ... .bind("keyword", Parameters.in(R2dbcType.JSON, keyword)) - 在实体类字段上标注JSON类型:
import org.springframework.data.relational.core.mapping.Column; @Column(columnDefinition = "JSON") private String keyword;
3. 更换官方R2DBC驱动
若dev.miku驱动问题无法解决,可改用MySQL官方提供的R2DBC驱动,兼容性更好:
<dependency> <groupId>com.mysql</groupId> <artifactId>mysql-r2dbc</artifactId> <version>8.0.33</version> </dependency>
同时移除原有的dev.miku:r2dbc-mysql依赖,配置文件中的URL需改为官方驱动格式:r2dbc:mysql://localhost:3306/db_name
内容的提问来源于stack exchange,提问作者Koishi
相关产品推荐
相关产品推荐

