PostgreSQL中JDBC的getColumnType()无法区分TIMESTAMPTZ与TIMESTAMP
区分PostgreSQL的TIMESTAMPTZ和TIMESTAMP类型(无需文本对比)
你遇到的问题很典型:PostgreSQL的TIMESTAMPTZ(带时区时间戳)和TIMESTAMP(无时区时间戳)在JDBC的getColumnType()方法中都返回Types.TIMESTAMP(值为93),但我们完全可以不用对比文本的方式来区分它们,下面是两种可靠的解决方案:
方案1:使用标准JDBC 4.2+的getSQLType()方法
从JDBC 4.2版本开始,ResultSetMetaData新增了getSQLType()方法,它返回JDBCType枚举类型,能精准区分带时区和不带时区的时间戳:
TIMESTAMPTZ对应JDBCType.TIMESTAMP_WITH_TIMEZONE(枚举值2013)TIMESTAMP对应JDBCType.TIMESTAMP(枚举值93)
修改你的代码如下:
try { Connection connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/tztestdb", "u", "p"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM TZTEST"); ResultSetMetaData metaData = resultSet.getMetaData(); for (int i = 1; i <= metaData.getColumnCount(); i++) { String columnName = metaData.getColumnName(i); JDBCType jdbcType = JDBCType.valueOf(metaData.getSQLType(i)); String typeName = metaData.getColumnTypeName(i); System.out.println(columnName + " > " + typeName + " > " + jdbcType); // 直接判断类型 if (jdbcType == JDBCType.TIMESTAMP_WITH_TIMEZONE) { System.out.println(" -> 这是TIMESTAMPTZ类型"); } else if (jdbcType == JDBCType.TIMESTAMP) { System.out.println(" -> 这是TIMESTAMP类型"); } } connection.close(); } catch (Exception e) { e.printStackTrace(); }
方案2:使用PostgreSQL驱动特定API
如果你用的是PostgreSQL官方JDBC驱动,可以将ResultSetMetaData强转为PGResultSetMetaData,调用getPGType()方法获取PostgreSQL内部的类型OID:
TIMESTAMPTZ的OID是1184TIMESTAMP的OID是1114
示例代码:
try { Connection connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/tztestdb", "u", "p"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM TZTEST"); PGResultSetMetaData metaData = (PGResultSetMetaData) resultSet.getMetaData(); for (int i = 1; i <= metaData.getColumnCount(); i++) { String columnName = metaData.getColumnName(i); String typeName = metaData.getColumnTypeName(i); int pgTypeOid = metaData.getPGType(i); System.out.println(columnName + " > " + typeName + " > PG OID: " + pgTypeOid); // 通过OID区分类型 if (pgTypeOid == 1184) { System.out.println(" -> 这是TIMESTAMPTZ类型"); } else if (pgTypeOid == 1114) { System.out.println(" -> 这是TIMESTAMP类型"); } } connection.close(); } catch (Exception e) { e.printStackTrace(); }
为什么getColumnType()会返回相同值?
早期JDBC规范里没有专门定义带时区的时间戳类型,PostgreSQL JDBC驱动为了兼容旧版JDBC API,把TIMESTAMPTZ映射到了Types.TIMESTAMP(值93),这就是两者返回相同数值的原因。而getColumnTypeName()返回的是数据库原生类型名称,所以能区分开。
内容的提问来源于stack exchange,提问作者bahtiyartan




