MySQL的Geometry数据处理之WKB方案

news2024/11/23 11:47:20

MySQL的Geometry数据处理之WKT方案:https://blog.csdn.net/qq_42402854/article/details/140134357

MySQL的Geometry数据处理之WKT方案中,介绍WTK方案的优点,也感受到它的繁琐和缺陷。比如:

  • 需要借助 ST_GeomFromText和 ST_AsText,让 SQL语句显得复杂。
select id, ST_AsText(geometry) AS geometry, update_time, create_time from geometry_data
  • 没有一种GeomFromText方案可以覆盖所有的Geometry结构,使得类似的SQL要写多份。比如:ST_GeomFromText不是万能的。针对"几何信息集合"(GeometryCollection)则需要使用ST_GeomCollFromText来转换。
insert into geometry_data(id, geometry, update_time, create_time) values
        (#{id}, ST_GeomFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())

insert into geometry_data(id, geometry, update_time, create_time) values
        (#{id}, ST_GeomCollFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())
  • 没有针对LinearRing(一种特殊的LineString)的处理方法。

MySQL的Geometry数据处理之WKB方案,则可以解决上述问题。

WKB全程Well-Known Binary,它是一种二进制存储几何信息的方法。

WKT方法,可以用字符串形式表达几何信息,如POINT (1 -1)。

WKB方法则表达为:0101000000000000000000F03F000000000000F0BF

这段二进制的拆解如下:
在这里插入图片描述

  1. byte order:可以是0或者1,它表示是大顶堆(0)还是小顶堆(1)存储。
  2. WKB type:表示几何类型。值的对应关系如下:
    ○ 1 Point
    ○ 2 LineString
    ○ 3 Polygon
    ○ 4 MultiPoint
    ○ 5 MultiLineString
    ○ 6 MultiPolygon
    ○ 7 GeometryCollection
  3. 剩下的是坐标信息。

虽然这个结构已经很基础,但是 MySQL的Geometry结构并不是WKB。准确的说,WKB只是 MySQL的Geometry结构中的一部分。它们的差异是,MySQL的Geometry结构是在WKB之前加了4个字节,用于存储SRID。

在这里插入图片描述

还有一点需要注意的是,MySQL存储Geometry数据使用的是小顶堆。所以WKB的Byte order字段值一定是1。 有了这些知识,我们就可以定义WKB类型的TypeHandler了。

一般我们会使用 org.locationtech.jts的 Geometry类来表达几何信息。

引入依赖:

        <!--Geometry工具库依赖-->
        <dependency>
            <groupId>org.locationtech.jts</groupId>
            <artifactId>jts-core</artifactId>
            <version>1.19.0</version>
        </dependency>

一、自定义类型处理器

项目中使用 MyBatis-Plus,自定义字段类型处理器来实现MySQL的Geometry数据处理之WKB方案。
MyBatis-Plus字段类型处理器:https://baomidou.com/guides/type-handler/

在 MyBatis 中,类型处理器(TypeHandler)扮演着 JavaType 与 JdbcType 之间转换的桥梁角色。它们用于在执行 SQL 语句时,将 Java 对象的值设置到 PreparedStatement 中,或者从 ResultSet 或 CallableStatement 中取出值。

1、完整TypeHandler类

@MappedTypes({Geometry.class})
@MappedJdbcTypes(JdbcType.BLOB)
public class GeometryTypeWKBHandler extends BaseTypeHandler<Geometry> {

    //private static final PrecisionModel PRECISION_MODEL = new PrecisionModel(PrecisionModel.FIXED); // 保留整数
    private static final PrecisionModel PRECISION_MODEL = new PrecisionModel(PrecisionModel.FLOATING); // 保留小数
    private static final Map<Integer, GeometryFactory> GEOMETRY_FACTORIES = new ConcurrentHashMap<>();


    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {
        byte[] bytes = serializeGeometry(parameter);
        ps.setBytes(i, bytes);
    }

    @Override
    public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {
        byte[] bytes = rs.getBytes(columnName);
        try {
            return deserializeGeometry(bytes);
        } catch (ParseException e) {
            throw new SQLException(e);
        }
    }

    @Override
    public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        byte[] bytes = rs.getBytes(columnIndex);
        try {
            return deserializeGeometry(bytes);
        } catch (ParseException e) {
            throw new SQLException(e);
        }
    }

    @Override
    public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        byte[] bytes = cs.getBytes(columnIndex);
        try {
            return deserializeGeometry(bytes);
        } catch (ParseException e) {
            throw new SQLException(e);
        }
    }

    /**
     * 序列化
     *
     * @param geometry
     * @return
     */
    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();
    }

    /**
     * 反序列化
     *
     * @param bytes
     * @return
     * @throws ParseException
     */
    private static Geometry deserializeGeometry(byte[] bytes) throws ParseException {
        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 = GEOMETRY_FACTORIES.computeIfAbsent(srid, i -> new GeometryFactory(PRECISION_MODEL, i));

        WKBReader reader = new WKBReader(geometryFactory);
        return reader.read(geometryBytes);
    }

}

2、序列化方法

    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();
    }

这段代码先从org.locationtech.jts.geom.Geometry中获取SRID码;

然后以小顶堆模式,使用WKBWriter将几何信息保存为WKB的二进制码。

然后申请比WKB大4个字节的空间,分别填入SRID和WKB。

这样整个内存结构就匹配Mysql内部的Geometry内存结构了。

3、反序列化方法

    private static Geometry deserializeGeometry(byte[] bytes) throws ParseException {
        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 = GEOMETRY_FACTORIES.computeIfAbsent(srid, i -> new GeometryFactory(PRECISION_MODEL, i));

        WKBReader reader = new WKBReader(geometryFactory);
        return reader.read(geometryBytes);
    }

这段代码会将Mysql内部的Geometry内存结构读出来,转换成小顶堆模式。

然后获取SRID,并以此创建GeometryFactory。

剩下的内容就是WKB的内存了,最后使用WKBReader将这段内存转换成org.locationtech.jts.geom.Geometry。

二、使用自定义类型处理器

在实体类中,通过 @TableField注解指定自定义的类型处理器。

确保 @TableField注解中的属性配置正确无误,特别是value属性是否匹配数据库的实际字段名,以及
jdbcType是否正确设置为JdbcType.BLOB,因为地理空间数据通常以BLOB形式存储。

创建表SQL语句:

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表';

1、DO类

几何数据使用 org.locationtech.jts.geom.Geometry类型。

@Getter
@Setter
@TableName("t_geo_wkb")
public class GeoWkbDO implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 创建时间
     */
    @TableField("create_time")
    private LocalDateTime createTime;

    /**
     * 修改时间
     */
    @TableField("update_time")
    private LocalDateTime updateTime;

    /**
     * 删除标记,0未删除,1已删除
     */
    @TableField("del_flag")
    private String delFlag;

    /**
     * 名称
     */
    @TableField("name")
    private String name;

    /**
     * geo_type
     */
    @TableField("geo_type")
    private String geoType;

    /**
     * geo几何数据-GCJ02
     */
    @TableField(value = "geo", typeHandler = GeometryTypeWKBHandler.class, jdbcType = JdbcType.BLOB)
    private Geometry geo;

}

2、Mapper.xml

在 Mapper文件中指定 typeHandler, jdbcType。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.charge.ws.core.mapper.GeoWkbMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.charge.ws.core.entity.GeoWkbDO">
        <id column="id" property="id"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
        <result column="del_flag" property="delFlag"/>
        <result column="name" property="name"/>
        <result column="geo_type" property="geoType"/>
        <result column="geo" property="geo" typeHandler="com.charge.ws.handler.jts.GeometryTypeWKBHandler"
                jdbcType="BLOB"/>
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id
        , create_time, update_time, del_flag, name, geo_type, geo
    </sql>

</mapper>

使用了WKB模式,SQL就会写的很简洁,而不需要使用ST_GeomFromText和ST_AsText转来转去。可以见得WKB模式让 SQL XML变得简单。

三、注册自定义类型处理器

如果使用 @TableField注解指定自定义类型处理器没有被执行,我们就需要显式注册自定义TypeHandler。

即在配置文件或启动类中 通过 TypeHandlerRegistry注册自定义的类型处理器。

@Configuration
@MapperScan("com.xxx.mapper")
public class MyBatisPlusConfig {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Bean
    public void registerCustomTypeHandlers() {
        sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().register(
                Geometry.class, // JavaType
                JdbcType.BLOB, // JdbcType
                GeometryTypeWKBHandler.class // 自定义TypeHandler
        );
    }

}

四、示例测试

1、单元测试

    @Autowired
    private GeoWkbService geoWkbService;

    @Autowired
    private GeoWkbMapper geoWkbMapper;

    @Test
    public void testListAll() {
        List<GeoWkbDO> doList = geoWkbService.listAll();
        System.out.println(doList);
    }

    @Test
    public void testInsert1() {
        // 点
        GeometryFactory geometryFactory = new GeometryFactory();
        Geometry point = geometryFactory.createPoint(new Coordinate(108.939645, 34.343205));

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("点");
        saveDO.setGeoType("1");
        saveDO.setGeo(point);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert2() {
        // 点集合
        GeometryFactory geometryFactory = new GeometryFactory();
        LineString lineString = geometryFactory
                .createLineString(new Coordinate[]{new Coordinate(108.939645, 34.343205), new Coordinate(108.939647, 34.343207),
                        new Coordinate(1, 1)});

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("点集合");
        saveDO.setGeoType("2");
        saveDO.setGeo(lineString);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert3() {
        // 线
        GeometryFactory geometryFactory = new GeometryFactory();
        LineString lineString = geometryFactory
                .createLineString(new Coordinate[]{new Coordinate(108.939645, 34.343205), new Coordinate(108.939647, 34.343207),
                        new Coordinate(2, 2), new Coordinate(3, 3)});

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("线");
        saveDO.setGeoType("3");
        saveDO.setGeo(lineString);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert4() {
        // 线集合
        GeometryFactory geometryFactory = new GeometryFactory();
        MultiLineString multiLineString = geometryFactory.createMultiLineString(new LineString[]{
                geometryFactory
                        .createLineString(new Coordinate[]{new Coordinate(108.939645, 34.343205), new Coordinate(108.939647, 34.343207)}),
                geometryFactory
                        .createLineString(new Coordinate[]{new Coordinate(108.939648, 34.343208), new Coordinate(108.939649, 34.343209)})
        });

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("线集合");
        saveDO.setGeoType("4");
        saveDO.setGeo(multiLineString);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert5() {
        // 面
        GeometryFactory geometryFactory = new GeometryFactory();
        Polygon polygon = geometryFactory.createPolygon(new Coordinate[]{new Coordinate(1, 1),
                new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(1, 1)});

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("面");
        saveDO.setGeoType("5");
        saveDO.setGeo(polygon);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert6() {
        // 面集合
        GeometryFactory geometryFactory = new GeometryFactory();
        MultiPolygon multiPolygon = geometryFactory.createMultiPolygon(new Polygon[]{
                geometryFactory.createPolygon(new Coordinate[]{new Coordinate(1, 1), new Coordinate(2, 2),
                        new Coordinate(3, 3), new Coordinate(1, 1)}),
                geometryFactory.createPolygon(new Coordinate[]{new Coordinate(4, 4), new Coordinate(5, 5),
                        new Coordinate(6, 6), new Coordinate(4, 4)})
        });

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("面集合");
        saveDO.setGeoType("6");
        saveDO.setGeo(multiPolygon);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert7() {
        // 几何信息集合
        GeometryFactory geometryFactory = new GeometryFactory();
        GeometryCollection geometryCollection = geometryFactory.createGeometryCollection(new Geometry[]{
                geometryFactory.createPoint(new Coordinate(1, 1)),
                geometryFactory.createLineString(new Coordinate[]{new Coordinate(1, 1), new Coordinate(2, 2)}),
                geometryFactory.createPolygon(new Coordinate[]{new Coordinate(1, 1), new Coordinate(2, 2),
                        new Coordinate(3, 3), new Coordinate(1, 1)})
        });

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("几何信息集合");
        saveDO.setGeoType("7");
        saveDO.setGeo(geometryCollection);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert8() {
        // 面-点集合
        GeometryFactory geometryFactory = new GeometryFactory();
        MultiPoint multiPoint = geometryFactory.createMultiPointFromCoords(
                new Coordinate[]{new Coordinate(1, 1), new Coordinate(2, 2), new Coordinate(3, 3)});

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("面-点集合");
        saveDO.setGeoType("8");
        saveDO.setGeo(multiPoint);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testInsert9() {
        // linearRing
        GeometryFactory geometryFactory = new GeometryFactory();
        LinearRing linearRing = geometryFactory.createLinearRing(new Coordinate[] { new Coordinate(1, 1),
                new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(1, 1) });

        GeoWkbDO saveDO = new GeoWkbDO();
        saveDO.setDelFlag(CommonConstants.DELETE_FLAG_NORMAL);
        saveDO.setName("linearRing");
        saveDO.setGeoType("9");
        saveDO.setGeo(linearRing);
        geoWkbMapper.insert(saveDO);
    }

    @Test
    public void testUpdateById() {
        GeometryFactory geometryFactory = new GeometryFactory();
        Coordinate coordinate = new Coordinate(2, 2);
        Geometry point = geometryFactory.createPoint(coordinate);
        GeoWkbDO updateDO = new GeoWkbDO();
        updateDO.setId(1L);
        updateDO.setGeo(point);
        geoWkbMapper.updateById(updateDO);
    }

在这里插入图片描述

2、返回VO序列化

因为 DO定义的是 Geometry类型,业务中流转没问题,但是我们希望返回的 VO对象的这个字段为字符串格式的内容。所以,我们需要指定字段的序列化器,下面我们自定义序列化器。

(1)自定义序列化器

public class GeometrySerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object obj, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (obj != null) {
            jsonGenerator.writeString(obj.toString());
        }
    }
}

(2)VO对象上添加序列化器

    @ApiModelProperty("geo几何数据-GCJ02")
    @JsonSerialize(using = GeometrySerializer.class)
    private Geometry geo;

在这里插入图片描述

参考文章:

  • Mysql的Geometry数据处理之WKB方案:https://fangliang.blog.csdn.net/article/details/139097706

— 求知若饥,虚心若愚。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1888410.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Gradio 教程四:Building Generative AI Applications with Gradio

文章目录 一、使用interface构建NLP应用1.1 构建文本摘要应用1.1.1 设置API密钥1.1.2 调用文本摘要API1.1.3 运行本地模型获取响应1.1.4 使用interface构建应用 1.2 构建命名实体识别应用1.2.1 调用NER任务API1.2.2 使用interface构建应用1.2.3 加入额外函数&#xff0c;合并to…

C语言实战 | 用户管理系统

近期推出的青少年防沉迷系统&#xff0c;采用统一运行模式和功能标准。在“青少年模式”下&#xff0c;未成年人的上网时段、时长、功能和浏览内容等方面都有明确的规范。防沉迷系统为青少年打开可控的网络空间。 01、综合案例 防沉迷系统的基础是需要一个用户管理系统管理用户…

Unity3d C#实现基于UGUI ScrollRect的轮播图效果功能(含源码)

前言 轮播功能是一种常见的页面组件&#xff0c;用于在页面中显示多张图片/素材并自动或手动进行切换&#xff0c;以提高页面的美观度和用户体验。主要的功能是&#xff1a;自动/手动切换;平滑的切换效果;导航指示器等。可惜Unity的UGUI系统里没有现成的实现该功能&#xff0c…

[Labview] 改写表格内容并储存覆盖Excel

在上一个功能的基础上&#xff0c;新增表格改写保存功能 [Labview] Excel读表 & 输出表单中选中的单元格内容https://blog.csdn.net/Katrina419/article/details/140120584 Excel修改前&#xff1a; 修改保存后&#xff0c;动态改写储存Excel&#xff0c;并重新写入新的表…

使用antd的<Form/>组件获取富文本编辑器输入的数据

前端开发中&#xff0c;嵌入富文本编辑器时&#xff0c;可以通过富文本编辑器自身的事件处理函数将数据传输给后端。有时候&#xff0c;场景稍微复杂点&#xff0c;比如一个输入页面除了要保存富文本编辑器的内容到后端&#xff0c;可能还有一些其他输入组件获取到的数据也一并…

Go - 8.func 函数使用

目录 一.引言 二.func 定义 三.func 实践 1.多个返回值 2.命名返回值 3.可变参数 四.总结 一.引言 函数是编程语言中的基本构建块&#xff0c;用于将代码组织成可重用的逻辑单元。函数可以接受输入参数&#xff0c;执行特定的操作&#xff0c;并返回结果。在 Go 语言&a…

设计IC行业SAP软件如何处理芯片成本计算

在集成电路(IC)设计与制造行业中&#xff0c;精确的成本计算对于维持健康的财务状况、优化生产流程以及保持市场竞争力至关重要。SAP软件&#xff0c;作为一种全面的企业资源规划(ERP)解决方案&#xff0c;为IC行业提供了强大且灵活的成本计算工具。以下是SAP软件如何处理芯片成…

【python】OpenCV—Feature Detection and Matching

参考学习来自OpenCV基础&#xff08;23&#xff09;特征检测与匹配 文章目录 1 背景介绍2 Harris角点检测3 Shi-Tomasi角点检测4 Fast 角点检测5 BRIEF 特征描述子6 ORB(Oriented Fast and Rotated Brief) 特征描述子7 SIFT(Scale Invariant Feature Transform) 特征描述子8 SU…

​​​​​​​​​​​​​​Spark Standalone集群环境

目录 Spark Standalone集群环境 修改配置文件 【workers】 【spark-env.sh】 【配置spark应用日志】 【log4j.properties】 分发到其他机器 启动spark Standalone 启动方式1&#xff1a;集群启动和停止 启动方式2&#xff1a;单独启动和停止 连接集群 【spark-shel…

基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建基于Hadoop的全分布式集群---任务1:运行环境说明

任务描述 项目的运行环境是基于Hadoop的全分布式模式集群。 任务的主要内容是规划集群节点及网络使用&#xff0c;准备初始环境&#xff0c;关闭防火墙和Selinux。 任务指导 1. 基于Hadoop的全分布式模式集群&#xff0c;如下图所示&#xff1b; 2. 硬软件环境&#xff1a;…

Android性能优化面试题经典之ANR的分析和优化

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 造成ANR的条件 以下四个条件都可以造成ANR发生&#xff1a; InputDispatching Timeout&#xff1a;5秒内无法响应屏幕触摸事件或键盘输入事件 …

《企业实战分享 · MyBatis 使用合集》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;如需交流&#xff…

Seatunnel本地模式快速测验

前言 SeaTunnel&#xff08;先前称为WaterDrop&#xff09;是一个分布式、高性能、易于扩展的数据集成平台&#xff0c;旨在实现海量数据的同步和转换。它支持多种数据处理引擎&#xff0c;包括Apache Spark和Apache Flink&#xff0c;并在某个版本中引入了自主研发的Zeta引擎…

虚拟机交叉编译基于ARM平台的opencv(ffmpeg/x264)

背景&#xff1a; 由于手上有一块rk3568的开发板&#xff0c;需要运行yolov5跑深度学习模型&#xff0c;但是原有的opencv不能对x264格式的视频进行解码&#xff0c;这里就需要将ffmpegx264编译进opencv。 但是开发板算力有限&#xff0c;所以这里采用在windows下&#xff0c;安…

2024年07年01日 Redis数据类型以及使用场景

String Hash List Set Sorted Set String&#xff0c;用的最多&#xff0c;对象序列化成json然后存储 1.对象缓存&#xff0c;单值缓存 2.分布式锁 Hash&#xff0c;不怎么用到 1.可缓存经常需要修改值的对象&#xff0c;可单独对对象某个属性进行修改 HMSET user {userI…

Element中的选择器组件Select (一级选择组件el-select)

简述&#xff1a;在 Element UI 中&#xff0c;ElSelect&#xff08;或简称为 Select&#xff09;是一个非常常用的选择器组件&#xff0c;它提供了丰富的功能来帮助用户从一组预定义的选项中选择一个或多个值。这里来简单记录一下 一. 组件和属性配置 <el-selectv-model&q…

经典FC游戏web模拟器--EmulatorJS

简介 EmulatorJS是一个基于JavaScript和Webassembly技术的虚拟环境的实现&#xff0c;可以在网页中运行各种经典FC游戏系统&#xff0c;支持任天堂、世嘉、雅达利等经典红白机。EmulatorJS的诞生使得诸如超级玛丽、坦克大战、魂斗罗等经典FC游戏能够以一种全新的方式回归。本文…

MySQL:高效的索引

数据库索引 1. 索引介绍1.1 创建索引1.2 查看索引 2. 索引应用2.1 前缀索引2.2 全文索引2.3 复合索引2.4 复合索引中的列顺序2.5 建立最佳索引2.6 使用索引排序2.7 覆盖索引 3. 维护索引4. 建立性能数据库 索引对大型和高并发数据库非常有用&#xff0c;因为它可以显著提升查询…

KVM虚拟机动态添加网卡

一、在宿主机上临时在线添加虚拟网卡&#xff0c;关机再开机失效 1、查看运行的虚拟机 [rootlocalhost img]# virsh list 2、添加NAT网卡&#xff0c;会自动获取192.168.122.X网段的IP virsh attach-interface hadoop01 --type network --source default 3、查看虚机mac …

vue+element-ui简洁完美实现个人博客“​响石潭 ​”

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.生活 ​编辑 4.文章详情 ​编辑 5.关于我 ​编辑 ​编辑 三、源码实现 1.项目依赖package.json 2.项目启动 3.首页源码 四、总结 一、项目介绍 本项目在线预览&#xff1a;点击访问 参考官网&#xff1…