You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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是1184
  • TIMESTAMP的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

火山引擎 最新活动