【问题标题】:JDBC: How to read MySQL point formatJDBC:如何读取 MySQL 点格式
【发布时间】:2019-01-19 22:06:51
【问题描述】:

我在 MySQL 中有一个 2D POINT 列。我使用 JDBC 将其读入 Java 对象。结果是一个字节[25]。我想知道这是什么格式,所以我可以将其转换为我的观点(例如双值)

点是这样设置的:

UPDATE ... SET point=GeomFromText('POINT(18 63)')

DB 中的结果字节:

0x00000000010100000000000000000032400000000000804F40

【问题讨论】:

  • 您能否分享有关POINT 列的表描述以及您目前如何尝试查询该表? GeomFromText('POINT(18 -63)') 是您在将数据插入列时使用的东西。
  • 列名真的是point吗?这是一个 MySQL 保留字,因此您应该在查询中使用 back tic (`point`) 对其进行转义,或者最好重命名该列。
  • 这只是一个示例名称,我将其命名为“start”。它与 ST_X/ST_Y 函数正常工作。但我需要为所有列使用 * 来选择它
  • 字节顺序标记是一个字节,POINT是常量8字节,坐标是两次8字节。似乎有一个可以转换的 WKBReader,使用 ResultSet.getBytes()
  • 感谢 Joop,WKBReader 工作正常。格式是小端,所以直接双转换给出了错误的结果。

标签: java mysql jdbc geometry point


【解决方案1】:

所以对于解决方案,我使用了来自 WKB 阅读器的代码:https://github.com/simplegeo/jts/tree/master/src/com/vividsolutions/jts/io

由于我不想包含所有内容,我只是使用代码从 ByteOrderValues.java 中读取字节序格式的双精度:

/**
     * Read a long from a byte buffer in big endian format.
     * @param buf must be 8 bytes
     */
    public static long readLongFromBytesBigEndian(byte[] buf) {
            return    (long) (buf[0] & 0xff) << 56
                    | (long) (buf[1] & 0xff) << 48
                    | (long) (buf[2] & 0xff) << 40
                    | (long) (buf[3] & 0xff) << 32
                    | (long) (buf[4] & 0xff) << 24
                    | (long) (buf[5] & 0xff) << 16
                    | (long) (buf[6] & 0xff) <<  8
                    | (long) (buf[7] & 0xff);
    }

    /**
     * Read a long from a byte buffer in little endian format.
     * @param buf must be 8 bytes
     */
    public static long readLongFromBytesLittleEndian(byte[] buf) {
            return    (long) (buf[7] & 0xff) << 56
                    | (long) (buf[6] & 0xff) << 48
                    | (long) (buf[5] & 0xff) << 40
                    | (long) (buf[4] & 0xff) << 32
                    | (long) (buf[3] & 0xff) << 24
                    | (long) (buf[2] & 0xff) << 16
                    | (long) (buf[1] & 0xff) <<  8
                    | (long) (buf[0] & 0xff);
    }

    /**
     * Read a long from a byte buffer in big or little endian format.
     * @param bigEndian true for big endian, false for little endian
     * @param buf must be 8 bytes
     */
    public static double readDoubleFromBytes(byte[] buf, boolean bigEndian) {
        long longVal =  bigEndian ? readLongFromBytesBigEndian(buf)
                : readLongFromBytesLittleEndian(buf);
        return Double.longBitsToDouble(longVal);
    }

    /**
     * Read a long from a byte buffer in big or little endian format.
     * @param bigEndian true for big endian, false for little endian
     * @param buf must be 8 bytes length after offset
     */
    public static double readDoubleFromBytes(byte[] buf, int offset, boolean bigEndian) {
        byte[] bufOf8Bytes = Arrays.copyOfRange(buf, offset, offset + 8);
        return readDoubleFromBytes(bufOf8Bytes, bigEndian);
    }

    /**
     * Read a coordinate from a byte array in WKB format.
     * @param wkbBytes must be 25 bytes long
     */
    public static Coordinate readCoordinateFromWkbBytes(byte[] wkbBytes) {
        // Points are stored in MySQL marked as big endian, but in reality is little endian. Not good
        boolean isBigEndian = false; // readIsWkbBigEndianByteOrder(wkbBytes[0]);
        double x = readDoubleFromBytes(wkbBytes, 9, isBigEndian);
        double y = readDoubleFromBytes(wkbBytes, 17, isBigEndian);
        Coordinate coordinate = new Coordinate();
        coordinate.setX(x);
        coordinate.setY(y);
        return coordinate;
    }

    public static boolean readIsWkbBigEndianByteOrder(byte b) {
        final byte BIG_ENDIAN = 0;
        final byte LITTLE_ENDIAN = 1;
        return b == BIG_ENDIAN;
    }

注意:我点的第一个字节,表示大/小端,设置为0,根据WKBReader应该是大端。但是我发现 littl endian 是实际的格式。

【讨论】:

    【解决方案2】:

    明确列出您从表中查询的所有列通常是一个好习惯,但如果您想使用通配符 (*) 以及 ST_X/Y() point property functions 作为坐标,您可以尝试使用表别名:

    SELECT ST_X(t.myPointColumn) as x_coordinate, ST_Y(t.myPointColumn) as y_coordinate, t.* 
          FROM myTable t WHERE ...
    

    在 Java 中,您可以使用

    myResultSet.getDouble("x_coordinate");
    myResultSet.getDouble("y_coordinate");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-29
      • 2016-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-11
      • 1970-01-01
      相关资源
      最近更新 更多