博客
关于我
MySQL的Geometry数据处理之WKB方案
阅读量:790 次
发布时间:2023-02-13

本文共 5453 字,大约阅读时间需要 18 分钟。

MySQL Geometry数据处理之WKT与WKB方案对比

在处理MySQL中的Geometry数据时,WKT(Well-Known Text)和WKB(Well-Known Binary)两种方案各有优劣。本文将从实际使用体验出发,对两种方案进行对比分析。


WKT方案的使用体验

WKT方案通过将几何数据以文本形式存储(如POINT (1 -1)),在SQL中实现简单易懂的操作。然而,其存在以下问题:

  • 操作复杂性

    需要借助ST_GeomFromTextST_AsText等函数,使得SQL语句显得复杂。例如:

    select id, ST_AsText(geometry) AS geometry, update_time, create_time from geometry_data
  • 类型转换限制

    ST_GeomFromText并非万能的转换函数。对于GeometryCollection类型,需要使用ST_GeomCollFromText,这增加了开发的复杂性。

  • 特定类型支持不足

    对于LinearRing等特殊类型,无法直接调用现有的转换函数,需要自行实现。


  • WKB方案的优势

    WKB(Well-Known Binary)通过二进制存储几何信息,能够有效解决上述问题。WKB的存储结构如下:

    0101000000000000000000F03F000000000000F0BF

    WKB存储结构解析

  • 字节顺序

    WKB的字节顺序可以是大顶堆(0)或小顶堆(1)。MySQL默认使用小顶堆存储。

  • 类型标识

    WKB类型字段对应以下值:

    • 1: Point
    • 2: LineString
    • 3: Polygon
    • 4: MultiPoint
    • 5: MultiLineString
    • 6: MultiPolygon
    • 7: GeometryCollection
  • 坐标信息

    存储点、线或面的坐标点。

  • WKB与MySQL Geometry的关系

    MySQL的Geometry结构实际上是基于WKB存储的,但增加了4个字节用于存储SRID(空间参考系标识符)。因此,WKB是Geometry的一部分,且MySQL默认使用小顶堆存储。


    WKB方案的实现

    自定义TypeHandler

    为了实现WKB方案,我们需要自定义TypeHandler。以下是完整的TypeHandler实现:

    import org.locationtech.jts.geom.Geometry;import org.locationtech.jts.geom.GeometryFactory;import org.locationtech.jts.geom.PrecisionModel;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.sql.Blob;import java.sql.SQLException;/** * WKB类型处理器实现 */@Componentpublic class GeometryTypeWKBHandler extends BaseTypeHandler
    { private static final PrecisionModel PRECISION_MODEL = new PrecisionModel(PrecisionModel.FLOATING); @Autowired private GeometryFactory geometryFactory; @Override public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException { byte[] bytes = rs.getBytes(columnName); return deserializeGeometry(bytes); } @Override public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException { byte[] bytes = rs.getBytes(columnIndex); return deserializeGeometry(bytes); } @Override public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { byte[] bytes = cs.getBytes(columnIndex); return deserializeGeometry(bytes); } @Override public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter) throws SQLException { byte[] bytes = serializeGeometry(parameter); ps.setBytes(i, bytes); } private byte[] serializeGeometry(Geometry geometry) { int srid = geometry.getSRID(); byte[] bytes = new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN).write(geometry); return ByteBuffer.allocate(bytes.length + 4) .order(ByteOrder.LITTLE_ENDIAN) .putInt(srid) .put(bytes) .array(); } private Geometry deserializeGeometry(byte[] bytes) throws SQLException { if (bytes == null) { return null; } ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); int srid = buffer.getInt(); byte[] geometryBytes = new byte[buffer.remaining()]; buffer.get(geometryBytes); GeometryFactory geometryFactory = geometryFactory; WKBReader reader = new WKBReader(geometryFactory); return reader.read(geometryBytes); }}

    TypeHandler注册

    在MyBatis Plus配置中,注册自定义TypeHandler:

    @Configurationpublic class MyBatisPlusConfig {    @Autowired    private SqlSessionFactory sqlSessionFactory;    @Bean    public void registerCustomTypeHandlers() {        sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().register(            Geometry.class,            JdbcType.BLOB,            GeometryTypeWKBHandler.class        );    }}

    数据库表定义

    CREATE TABLE `t_geo_wkb` (    `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',    `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',    `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',    `del_flag` char(1) DEFAULT '0' COMMENT '删除标记,0未删除,1已删除',    `name` varchar(255) DEFAULT NULL COMMENT '名称',    `geo_type` varchar(255) DEFAULT NULL COMMENT 'geo_type',    `geo` geometry NOT NULL COMMENT 'geo几何数据-GCJ02',    PRIMARY KEY (`id`),    SPATIAL KEY `idx_geo` (`geo`) COMMENT '空间数据索引')ENGINE=InnoDB COMMENT='几何数据wkb表';

    实体类映射

    import org.springframework.beans.annotation.AnnotationConfig;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import static org.mybatis.mybatisplus.annotations.TableField;@MapperScan("com.charge.ws.core.mapper")public class GeoWkbDO extends BaseDO {    private static final long serialVersionUID = 1L;    @TableId(value = "id", type = IdType.AUTO)    private Long id;    @TableField("create_time")    private LocalDateTime createTime;    @TableField("update_time")    private LocalDateTime updateTime;    @TableField("del_flag")    private String delFlag;    @TableField("name")    private String name;    @TableField("geo_type")    private String geoType;    @TableField(        value = "geo",        typeHandler = GeometryTypeWKBHandler.class,        jdbcType = JdbcType.BLOB    )    private Geometry geo;}

    SQL插入示例

    insert into geometry_data(id, geometry, update_time, create_time) values    ('#{id}', #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())

    总结

    通过对比WKT和WKB方案,我们发现WKB方案在存储和处理Geometry数据方面具有显著优势。WKB的二进制存储方式能够有效解决传统方案的复杂性问题,同时MySQL的Geometry结构与WKB兼容,通过自定义TypeHandler可以实现高效的数据操作。

    转载地址:http://lpdfk.baihongyu.com/

    你可能感兴趣的文章
    Mysql存表情符号发生错误
    查看>>
    MySQL学习-group by和having
    查看>>
    MySQL学习-MySQL数据库事务
    查看>>
    MySQL学习-MySQL条件查询
    查看>>
    MySQL学习-SQL语句的分类与MySQL简单查询
    查看>>
    MySQL学习-子查询及limit分页
    查看>>
    MySQL学习-排序与分组函数
    查看>>
    MySQL学习-连接查询
    查看>>
    Mysql学习总结(10)——MySql触发器使用讲解
    查看>>
    Mysql学习总结(12)——21分钟Mysql入门教程
    查看>>
    Mysql学习总结(13)——使用JDBC处理MySQL大数据
    查看>>
    Mysql学习总结(15)——Mysql错误码大全
    查看>>
    Mysql学习总结(17)——MySQL数据库表设计优化
    查看>>
    Mysql学习总结(18)——Mysql主从架构的复制原理及配置详解
    查看>>
    Mysql学习总结(19)——Mysql无法创建外键的原因
    查看>>
    Mysql学习总结(20)——MySQL数据库优化的最佳实践
    查看>>
    Mysql学习总结(21)——MySQL数据库常见面试题
    查看>>
    Mysql学习总结(22)——Mysql数据库中制作千万级测试表
    查看>>
    Mysql学习总结(23)——MySQL统计函数和分组查询
    查看>>
    Mysql学习总结(24)——MySQL多表查询合并结果和内连接查询
    查看>>