R2DBC MySQL如何绑定数组字段 解决Spanner绑定失败异常
直接传入Java原生数组(如String[])调用R2DBC SPI的bind方法时,会抛出com.google.cloud.spanner.r2dbc.BindingFailureException: Can't find a binder for type: class [Ljava.lang.String异常,核心原因是Cloud Spanner R2DBC驱动内置的参数绑定器没有匹配JVM原生数组类型的实现,仅识别驱动遵循R2DBC标准实现的Array类型实例,Spanner原生客户端、JDBC驱动的数组绑定逻辑无法直接复用到R2DBC场景。
标准SPI写法(跨驱动兼容)
不要直接传入原生数组,先通过Connection实例的createArrayOf方法构造R2DBC标准Array实例再完成绑定,代码示例:
// 假设已获取R2DBC Connection实例connection、待执行Statement实例statement String[] stringArr = {"goods", "sports", "reading"}; // 构造R2DBC Array实例,第一个参数传入Spanner字段对应的元素类型名,字符串数组对应STRING io.r2dbc.spi.Array arrayParam = connection.createArrayOf("STRING", stringArr).block(); // 绑定到对应占位符,示例占位符为$1 statement.bind("$1", arrayParam);
常见类型对应参数名:
- 字符串数组:
STRING - 长整型数组:
INT64 - 浮点型数组:
FLOAT64 - 布尔数组:
BOOL - 时间戳数组:
TIMESTAMP
Spanner R2DBC专属写法(无额外依赖)
如果不需要兼容其他R2DBC驱动,可以直接使用Spanner R2DBC驱动自带的工具类构造数组参数,不需要提前获取Connection实例:
import com.google.cloud.spanner.r2dbc.util.Arrays; String[] stringArr = {"goods", "sports", "reading"}; statement.bind("$1", Arrays.toArray(stringArr));
框架适配说明
如果使用Spring Data R2DBC操作Spanner,不需要手动构造Array实例,Repository接口方法直接传入原生Java数组即可,框架内置的类型转换器会自动完成参数转换。
MySQL没有原生数组数据类型,业务中通常用JSON类型存储数组结构,R2DBC MySQL驱动不支持createArrayOf方法构造数组参数,需要先将数组序列化为JSON格式字符串再绑定:
import com.fasterxml.jackson.databind.ObjectMapper; // 示例:绑定字符串数组到JSON类型字段 String[] stringArr = {"goods", "sports", "reading"}; String jsonArr = new ObjectMapper().writeValueAsString(stringArr); statement.bind("$1", jsonArr);
如果使用Spring Data R2DBC操作MySQL,只要配置了Jackson JSON类型转换器,直接传入原生数组即可自动完成序列化绑定。
- 不要直接将
java.util.List实例、JVM原生数组作为参数传入bind方法,除Spring Data R2DBC等做了上层封装的框架外,原生驱动不会自动做类型转换 - 构造数组参数时传入的元素类型必须和数据库表字段定义的元素类型一致,否则执行阶段会抛出类型不匹配异常
内容的提问来源于stack exchange,提问作者johnnesto

