JDBC 的 Array 与 Struct 在不同数据库上的支持天差地别。这篇用 PostgreSQL 把数组用到极致,用 MySQL 看清「不支持」是什么样子,并检查复合类型能走到哪一步。
插入多种元素类型的数组:1 行
ints 列类型 _int4 /2003 getBaseTypeName=int4 getBaseType=4 getArray → Integer[4][1, 2, null, 4]
txt 列类型 _text /2003 getBaseTypeName=text getBaseType=12 getArray → String[8][a,b, quote"here, back\slash, {brace}, 中文, NULL, , space ]
nums 列类型 _numeric /2003 getBaseTypeName=numeric getBaseType=2 getArray → BigDecimal[2][1.50, -0.001]
ts 列类型 _timestamp/2003 getBaseTypeName=timestamp getBaseType=93 getArray → Timestamp[2][2026-01-02 03:04:05.678, null]
ids 列类型 _uuid /2003 getBaseTypeName=uuid getBaseType=1111 getArray → UUID[1][123e4567-e89b-12d3-a456-426614174000]
bools 列类型 _bool /2003 getBaseTypeName=bool getBaseType=-7 getArray → Boolean[3][true, false, null]
bytes 列类型 _bytea /2003 getBaseTypeName=bytea getBaseType=-2 getArray → byte[][2][byte[3][1, 2, 3], byte[0][]]
grid 列类型 _int4 /2003 getBaseTypeName=int4 getBaseType=4 getArray → Integer[][3][Integer[2][1, 2], Integer[2][3, 4], Integer[2][5, 6]]
getString 看数组的文本形式:ints = “{1,2,NULL,4}”;txt = “{"a,b","quote\"here","back\\slash","{brace}",中文,"NULL",""," space "}”
getObject("ints") 的类型:org.postgresql.jdbc.PgArray
txt 数组里的各元素是否原样还原:true;“NULL” 字符串与 SQL NULL 的区别:ta[5] = NULL(String)
二维数组 getArray():Integer[][] Integer[][3][Integer[2][1, 2], Integer[2][3, 4], Integer[2][5, 6]];元素 [0] 的类型 Integer[]
getArray(2, 2)(从第 2 个元素起取 2 个,下标从 1 开始):Integer[2][2, null];getArray(1, 10) 超过长度:PSQLException(22000): The array index is out of range: 11, number of elements: 4.;getArray(0, 2):PSQLException(22000): The array index is out of range: 0;getArray(5, 1):PSQLException(22000): The array index is out of range: 6, number of elements: 4.
array.getResultSet()(第 1 列是下标,第 2 列是值):[1:1, 2:2, 3:null, 4:4];列数 2
free() 之后 getArray:null
空数组与 NULL 数组:空数组 getArray → Integer[0][];NULL 数组 getArray = null(wasNull true);getString 空数组 “{}”
元素类型与数组类型不匹配:PSQLException(22P02): ERROR: invalid input syntax for type integer: "x"
createArrayOf 的类型名写错("int" / "INTEGER" / "int4" / "_int4" / "nosuchtype"):[int=ok, INTEGER=ok, int4=ok, _int4=PSQLException(42602): Unable to find server array type for provided name _int4., integer[]=PSQLException(42602): Unable to find server array type for provided name integer[]., nosuchtype=PSQLException(42602): Unable to find server array type for provided name nosuchtype.]
createArrayOf("integer", Object[] 里混入 Long):成功 {"1","2"}
ps.setObject(i, Integer[]) 直接传 Java 数组:cardinality = 3
ps.setObject(i, int[])(基本类型):cardinality = 3 createArrayOf:SQLFeatureNotSupportedException(null): null
createStruct:SQLFeatureNotSupportedException(null): null
DatabaseMetaData.supportsGetGeneratedKeys 等无关;JSON 数组列 getObject:String “[1, 2, 3]”;rs.getArray → SQLFeatureNotSupportedException(null): null
setArray 到 PreparedStatement:SQLFeatureNotSupportedException(null): null
setObject(1, new Integer[]{1,2}):查询返回 132 字节,开头 aced00057572(aced0005 是 Java 序列化流的魔数——数组被当作序列化对象传给了服务器)
IN 列表替代:500 个占位符的 IN → 500 行 10 个 id:= ANY(?) 0.14 ms(10 行);IN (?,…) 0.15 ms(10 行)
1000 个 id:= ANY(?) 0.56 ms(1000 行);IN (?,…) 1.12 ms(1000 行)
10000 个 id:= ANY(?) 4.40 ms(10000 行);IN (?,…) 10.17 ms(10000 行)
30000 个 id:= ANY(?) 12.28 ms(30000 行);IN (?,…) 成功
40000 个 id:= ANY(?) 14.36 ms(33334 行);IN (?,…) 成功
没有元素时 = ANY(空数组):0 行;空 IN () 的 SQL:PSQLException(42601): ERROR: syntax error at or near ")"
ANY(?) 里含 NULL 元素:2 行;NOT IN 加 NULL 的陷阱 id <> all(含 NULL):0 行(预期 99998,NULL 使整个比较未知) createStruct:SQLFeatureNotSupportedException(0A000): Method org.postgresql.jdbc.PgConnection.createStruct(String, Object[]) is not yet implemented.
用 PGobject(type=point3, value="(1,2,…)") 插入复合类型:1 行
getObject 复合类型:org.postgresql.util.PGobject;getType = point3;getValue = “(1,2,"he said ""hi""")”;getString = “(1,2,"he said ""hi""")”;metadata 类型 point3/2002
rs.getObject(1, java.sql.Struct.class) :PSQLException(22023): conversion to interface java.sql.Struct from point3 not supported
拆开成列:(p).x = 1;(p).label = “he said "hi"”(服务端展开比客户端解析文本更可靠)
PgStruct 类 / Struct 接口:org.postgresql.jdbc 里有没有 PgStruct —— ClassNotFoundException: org.postgresql.jdbc.PgStruct
复合类型数组 getArray:baseTypeName=point3;元素类型 PGobject;元素 [(1,2,a), (3,4,b)]
getObject(列, Map) 自定义类型映射:SQLFeatureNotSupportedException(0A000): Method org.postgresql.jdbc.PgResultSet.getObjectImpl(int,Map) is not yet implemented.
getTypeMap:{} 1000 个元素:createArrayOf 3 ms;INSERT 2 ms;getArray → Integer[1000][0, 1, 2, 3, 7 ms
100000 个元素:createArrayOf 5 ms;INSERT 6 ms;getArray → Integer[100000][0, 1, 2, 33 ms
1000000 个元素:createArrayOf 6 ms;INSERT 49 ms;getArray → Integer[1000000][0, 1, 2, 158 ms
int[] 基本类型数组(getArray 返回的是装箱的 Integer[])的内存/用途:见上一项的 getArray 类型