0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKB方案

news/2024/7/25 2:31:12/文章来源:https://blog.csdn.net/breaksoftware/article/details/139097706

大纲

  • 序列化
  • 反序列化
  • 完整TypeHandler
  • SQL XML
    • 完整XML
  • Mapper
  • 测试代码
  • 代码

在《0基础学习Mybatis系列数据库操作框架——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要写多份。
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)的处理方法。

而本文介绍的WKB方法,则可以解决上述问题。
WKB全程Well-Known Binary,它是一种二进制存储几何信息的方法。
在《0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKT方案》中介绍的WKT方法,可以用字符串形式表达几何信息,如POINT (1 -1)。
WKB则表达为

0101000000000000000000F03F000000000000F0BF

这段二进制的拆解如下

ComponentSizeValue
Byte order1 byte01
WKB type4 bytes01000000
X coordinate8 bytes000000000000F03F
Y coordinate8 bytes000000000000F0BF

byte order可以是0或者1,它表示是大顶堆(0)还是小顶堆(1)存储。
WKB type表示几何类型。值的对应关系如下:

  • 1 Point
  • 2 LineString
  • 3 Polygon
  • 4 MultiPoint
  • 5 MultiLineString
  • 6 MultiPolygon
  • 7 GeometryCollection

剩下的是坐标信息。

虽然这个结构已经很基础,但是**Mysql的Geometry结构并不是WKB。准确的说,WKB只是Mysql的Geometry结构中的一部分。**它们的差异是,Mysql的Geometry结构是在WKB之前加了4个字节,用于存储SRID。
在这里插入图片描述
还有一点需要注意的是,Mysql存储Geometry数据使用的是小顶堆。所以WKB的Byte order字段值一定是1。
有了这些知识,我们就可以定义WKB类型的TypeHandler了。

序列化

这段代码先从org.locationtech.jts.geom.Geometry中获取SRID码;然后以小顶堆模式,使用WKBWriter将几何信息保存为WKB的二进制码。然后申请比WKB大4个字节的空间,分别填入SRID和WKB。这样整个内存结构就匹配Mysql内部的Geometry内存结构了。

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

反序列化

这段代码会将Mysql内部的Geometry内存结构读出来,转换成小顶堆模式。然后获取SRID,并以此创建GeometryFactory。剩下的内容就是WKB的内存了,最后使用WKBReader将这段内存转换成org.locationtech.jts.geom.Geometry。

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

完整TypeHandler

package org.example.typehandlers;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ByteOrderValues;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class GeometryTypeWKBHandler extends BaseTypeHandler<Geometry>  {private static final PrecisionModel PRECISION_MODEL = new PrecisionModel(PrecisionModel.FIXED);private static final Map<Integer, GeometryFactory> GEOMETRY_FACTORIES = new ConcurrentHashMap<>();@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {byte[] bytes = serializeGeometry(parameter);ps.setBytes(i, bytes);}@Overridepublic Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {byte[] bytes = rs.getBytes(columnName);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}@Overridepublic Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {byte[] bytes = rs.getBytes(columnIndex);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}@Overridepublic Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {byte[] bytes = cs.getBytes(columnIndex);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}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);}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();}
}

SQL XML

使用了WKB模式,SQL就会写的很简洁,而不需要用ST_GeomFromText和ST_AsText转来转去。比如之前因为要用ST_AsText处理返回值,导致需要写明每个返回的字段。而使用WKB后,可以写成

    <resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKBHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select * from geometry_data</select>

作为对比可以看下WKT的模式,如下。

    <resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKTHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select id, ST_AsText(geometry) AS geometry, update_time, create_time from geometry_data</select>

插入操作也会变得简单,下面是WKB模式

    <insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</insert>

而WKT模式,因为不能使用ST_GeomFromText处理GeometryCollection,导致只能拆成两条SQL。如下

    <insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">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><insert id="insertGeometryCollection" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, ST_GeomCollFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())</insert>

可以见得WKB模式让SQL XML变得简单。

完整XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- AllTypeMapper-1.xml -->
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.GeometryDataWKBMapper"><resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKBHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select * from geometry_data</select><select id="find" resultMap="GeometryDataResultMap">select * from geometry_data where id = #{id}</select><insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</insert><insert id="insertList" parameterType="list">insert into geometry_data(id, geometry, update_time, create_time) values<foreach item="item" collection="list" separator=",">(#{item.id}, #{item.geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</foreach></insert><update id="updateOne" parameterType="org.example.model.GeometryData">update geometry_data set geometry = #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, update_time = now() where id = #{id} </update>
</mapper>

Mapper

package org.example.mapper;import java.util.List;import org.example.model.GeometryData;public interface GeometryDataWKBMapper {public List<GeometryData> findAll();public GeometryData find(Long id);public Long insertOne(GeometryData geometryData);public Long insertList(List<GeometryData> geometryDataList);public Long updateOne(GeometryData geometryData);
} 

测试代码

相较于WKT模式,我们给WKB模式的测试用例增加了LinearRing类型。这是WKT模式所不支持的。

package org.example;import static org.junit.jupiter.api.Assertions.fail;import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.mapper.GeometryDataWKBMapper;
import org.example.model.GeometryData;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.geom.MultiPoint;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;public class GeometryDataWKBTest {private static SqlSessionFactory sqlSF;@BeforeAllstatic void CreateSessionFactory() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis/config/mybatis-config-geometry-wkb.xml");sqlSF = new SqlSessionFactoryBuilder().build(in);}@Testpublic void testFindAll() {List<GeometryData> all = null;try (SqlSession session = sqlSF.openSession()) {all = session.getMapper(GeometryDataWKBMapper.class).findAll();} catch (Exception e) {System.out.println(e.getMessage());}for (GeometryData a : Objects.requireNonNull(all)) {System.out.println(a.getGeometry());}}@Testpublic void testFind() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData one = GeometryDataWKBMapper.find(1L);System.out.println(one.getGeometry());} catch (Exception e) {System.out.println(e.getMessage());}}@Testpublic void testInsert() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(1, 1);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setGeometry(geometry);long count = GeometryDataWKBMapper.insertOne(geometryData);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}@Testpublic void testUpdate() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(2, 2);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setId(1L);geometryData.setGeometry(geometry);long count = GeometryDataWKBMapper.updateOne(geometryData);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}@Testpublic void testInsertList() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);List<GeometryData> geometryDataList = new ArrayList<>();{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(3, 3);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setGeometry(geometry);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();LineString lineString = geometryFactory.createLineString(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2) });geometryData.setGeometry(lineString);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();MultiLineString multiLineString = geometryFactory.createMultiLineString(new LineString[] {geometryFactory.createLineString(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2) }),geometryFactory.createLineString(new Coordinate[] { new Coordinate(3, 3), new Coordinate(4, 4) })});geometryData.setGeometry(multiLineString);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();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) })});geometryData.setGeometry(multiPolygon);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();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) });geometryData.setGeometry(linearRing);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();MultiPoint multiPoint = geometryFactory.createMultiPointFromCoords(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2), new Coordinate(3, 3) });geometryData.setGeometry(multiPoint);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();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) });geometryData.setGeometry(polygon);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();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) })});geometryData.setGeometry(geometryCollection);geometryDataList.add(geometryData);}long count = GeometryDataWKBMapper.insertList(geometryDataList);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}
}

在这里插入图片描述

代码

https://github.com/f304646673/mybatis_demo

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何创建 Gala Games 账户:解决 Cloudflare 验证指南 2024

Gala Games 站在数字娱乐新时代的前沿&#xff0c;将区块链技术与游戏相结合&#xff0c;重新定义了所有权和奖励。本文将引导您创建 Gala Games 账户并使用 CapSolver 解决 Cloudflare 验证难题&#xff0c;确保您顺利进入这一创新的生态系统。 什么是 Gala Games&#xff1f…

Dockerfile使用

1.Dockerfile是什么 官网地址 https://docs.docker.com/reference/dockerfile/概念 是什么 Dockerfile 是用于构建 Docker 镜像的文本文件&#xff0c;它包含一系列的指令&#xff08;instructions&#xff09;和参数&#xff0c;用于描述如何构建和配置镜像。 Dockerfile 是…

在树莓派3B+中下载opencv(遇到的各种问题及解决)

目录 前言 1、删除原版本下新版本 2、python虚拟环境 3、python版本共存换链接——给版本降低 4、烧录之前版本的文件&#xff08;在清华源中可以找&#xff0c;不用官网的烧录文件就行&#xff1b; 比如&#xff1a;&#xff08;balenaEtcher&#xff09;重新烧录有问题…

利用迭代方法求解线性方程组(Matlab)

一、问题描述 利用迭代方法求解线性方程组。 二、实验目的 掌握Jacobi 方法和Gauss-Seidel 方法的原理&#xff0c;能够编写代码实现两种迭代方法&#xff1b;能够利用代码分析线性方程组求解中的误差情况。 三、实验内容及要求 用代码实现&#xff1a;对下列方程中重新组织…

多商户消费券系统源码(ThinkPHP+FastAdmin+微信公众号)

打造智能促销新体验 一、引言&#xff1a;消费券系统的时代意义 在当今这个数字化高速发展的时代&#xff0c;电子商务和移动支付已经成为人们日常生活的重要组成部分。随着市场竞争的加剧&#xff0c;多商户消费券系统作为一种创新的促销手段&#xff0c;正逐渐受到商家和消…

IP协议说明

文章目录 前言一、IP协议的简介二、IP数据报1.IP 数据报结构2.IP 数据报的分片解析3.IP 数据报的分片重装 三、IP 数据报的输出四、IP 数据报的输入 前言 IP 指网际互连协议&#xff0c; Internet Protocol 的缩写&#xff0c;是 TCP/IP 体系中的网络层协议。设计 IP 的目的是…

mysql中text,longtext,mediumtext区别

文章目录 一.概览二、字节限制不同三、I/O 不同四、行迁移不同 一.概览 在 MySQL 中&#xff0c;text、mediumtext 和 longtext 都是用来存储大量文本数据的数据类型。 TEXT&#xff1a;TEXT 数据类型可以用来存储最大长度为 65,535(2^16-1)个字符的文本数据。如果存储的数据…

生成式AI的GPU网络技术架构

生成式AI的GPU网络 引言&#xff1a;超大规模企业竞相部署拥有64K GPU的大型集群&#xff0c;以支撑各种生成式AI训练需求。尽管庞大Transformer模型与数据集需数千GPU&#xff0c;但实现GPU间任意非阻塞连接或显冗余。如何高效利用资源&#xff0c;成为业界关注焦点。 张量并…

SpringCloud系列(22)--Ribbon默认负载轮询算法原理及源码解析

前言&#xff1a;在上一篇文章中我们介绍了如何去切换Ribbon的负载均衡模式&#xff0c;而本章节内容则是介绍Ribbon默认负载轮询算法的原理。 1、负载轮询算法公式 rest接口第N次请求数 % 服务器集群总数 实际调用服务器下标&#xff08;每次服务器重启后rest接口计数从1开始…

K210 数字识别 笔记

一、烧写固件 连接k210开发板&#xff0c;点开烧录固件工具&#xff0c;选中固件&#xff0c;并下载 二、模型训练 网站&#xff1a;MaixHub 1、上传文件 2、开始标记数据 添加9个标签&#xff0c;命名为1~9&#xff0c;按键盘w开始标记&#xff0c;键盘D可以下一张图片&…

C语⾔:内存函数

1. memcpy使⽤和模拟实现&#xff08;对内存块的复制&#xff0c;不在乎类型&#xff09; void * memcpy ( void * destination, const void * source, size_t num ); • 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。 • 这个函数在遇…

【LabVIEW FPGA入门】同步C系列模块

1.同步使用循环定时器VI计时循环速率的系列模块 数字模块SAR ADC 模块多路复用模块 数字通道可以在一个时钟周期内执行。模拟通道需要多个时钟周期。 同步模拟模块的每个通道有一个 ADC&#xff0c;采集的数据在通道之间没有明显的偏差。多路复用模块使用多路复用器通过单个 A…

[杂项]优化AMD显卡对DX9游戏(天谕)的支持

目录 关键词平台说明背景RDNA 1、2、3 架构的显卡支持游戏一、 优化方法1.1 下载 二、 举个栗子&#xff08;以《天谕》为例&#xff09;2.1 下载微星 afterburner 软件 查看游戏内信息&#xff08;可跳过&#xff09;2.2 查看D3D9 帧数2.3 关闭游戏&#xff0c;替换 dll 文件2…

PHP开发入门

PHP官网&#xff1a;PHP: Hypertext Preprocessor apache官网&#xff1a;https://httpd.apache.org/ 一、搭建PHP环境 下载apache 进入官网点击download 选择下载windows版本文件 点击进入下载界面 点击下载64位版本文件 下载后解压文件 解压文件后进入 D:\httpd-2.4.59-24…

电脑卸载linux安装windows后每次开机都出现grub

原因分析 这是因为电脑硬盘中还存在linux系统的引导程序&#xff0c;并且启动顺序还在windows之前&#xff0c;有时候通过bios根本找不到它的存在&#xff0c;以至于每次windows开机出现grub之后都要输入exit退出linux的引导之后才能使得电脑进入windows&#xff0c;这个有时会…

【测评】香橙派 AIpro上手初体验

AI毋庸置疑是近年来&#xff0c;热度最高的技术之一&#xff0c;作为一名工程师拥抱新技术的同时不可或缺的需要一块强悍的开发板&#xff0c;香橙派 AIpro除了拥有好看的皮囊之外&#xff0c;还拥有一个有趣且充满魅力的灵魂。作为一位长期活跃在嵌入式开发领域的工程师&#…

《当微服务遇上Ribbon:一场负载均衡的华丽舞会》

在微服务的厨房里&#xff0c;如何确保每一道服务都恰到好处&#xff1f;揭秘Spring Cloud Ribbon如何像大厨一样精心调配资源&#xff0c;让负载均衡变得像烹饪艺术一样简单&#xff01; 文章目录 Spring Cloud Ribbon 详解1. 引言微服务架构中的负载均衡需求Spring Cloud Rib…

jmeter服务器性能监控分析工具ServerAgent教程

ServerAgent介绍&#xff1a;支持监控CPU&#xff0c;memory&#xff0c;磁盘&#xff0c;网络等&#xff0c;和JMeter集成&#xff0c;在JMeter的图形界面中&#xff0c;可以实时看到监控的数据&#xff0c;但是&#xff0c;它只能监控硬件资源使用情况。 不能监控应用服务 S…

LLM提示工程的技巧

1. 从简单开始&#xff08;Start Simple&#xff09; 避免在一开始就增加太多的复杂性。 从简单的提示开始&#xff0c;然后在后续提示中添加更多信息和上下文。 这样&#xff0c;提示就是一个迭代过程&#xff0c;提示在此过程中进一步发展。 从简单的开始&#xff0c;就有足…

小红书推流机制底层逻辑

小红书推流机制底层逻辑 很多做运营的朋友问小红薯怎么玩❓ 小红书的核心逻辑流量是不是玄学❓ 今天就来说说小红书的流量算法机制&#x1f525; ①电脑审核 ②分配初始流量 ③增加流量 ④推荐结束