ThinkPHP怎么实现地理位置查询_ThinkPHP经纬度距离方法【方法】

陌磊君_7334

陌磊君_7334

2026-04-07

396人浏览

原创

thinkphp 6.x 中计算两点经纬度距离应优先使用 mysql 5.7+ 的 st_distance_sphere(支持空间索引、精度高),php 层可手写 haversine 公式但须统一单位为弧度、地球半径取 6371 km;地址转经纬度需调用高德/百度等第三方 api 并做好缓存、异常兜底与异步请求;mysql 表需增设 point 字段并建立 spatial index,否则查询性能骤降;db::raw 写 haversine 易因未转弧度或参数错位导致结果不准,st_distance_sphere 更稳妥。

thinkphp怎么实现地理位置查询_thinkphp经纬度距离方法【方法】

ThinkPHP 6.x 中如何计算两点经纬度距离

直接用 think\helper\Str 或数据库函数更高效,TP 自身不提供内置的地理距离计算方法。别在 Db::raw() 里硬写 Haversine 公式却忽略索引失效问题——这是最常踩的坑。

推荐两种稳妥方式:

  • 数据库层计算(MySQL 5.7+):用 ST_Distance_Sphere,支持空间索引,查得快、精度高
  • PHP 层计算(兼容低版本或简单场景):手写 Haversine,但必须注意单位统一(度 → 弧度)、地球半径取值(6371 km 更常用)

示例(MySQL 空间查询):

SELECT id, name, 
  ST_Distance_Sphere(
    POINT(116.48, 39.92), 
    POINT(longitude, latitude)
  ) AS distance 
FROM shops 
WHERE ST_Distance_Sphere(
    POINT(116.48, 39.92), 
    POINT(longitude, latitude)
  ) <h3>ThinkPHP 中怎么把地址转成经纬度(逆地理编码)</h3><p>TP 不处理地址解析,得调第三方 API。高德、百度、腾讯地图都提供 HTTP 接口,关键不是“怎么发请求”,而是“怎么缓存 + 防错”。</p><p>常见错误:</p>
  • 每次查地址都实时调 API → 耗时、限流、白名单没配好直接 403
  • 没对空结果或异常响应做兜底 → NULL 写进数据库,后续距离计算全崩
  • 用 file_get_contents 同步阻塞请求 → 页面卡死

实操建议:

  • 用 think\Http 或 guzzlehttp/guzzle 发异步/带超时的 GET
  • 查前先查本地缓存表(address_cache),字段含 address、lng、lat、expires_at
  • 失败时返回默认坐标(如城市中心点),并记录日志,避免中断业务流程

MySQL 表结构怎么设计才支持高效地理查询

光有 lng 和 lat 两个 decimal 字段是不够的。不建空间索引,ST_Distance_Sphere 就没法加速,数据一过万就明显变慢。

ThinkPHP5.1企业站点快速开发-源码课件
ThinkPHP5.1企业站点快速开发-源码课件

ThinkPHP5.1企业站点快速开发

下载

必须做三件事:

  • 加一个 POINT 类型字段,比如 location,用 POINT(lng, lat) 初始化
  • 给该字段建空间索引:SPATIAL INDEX idx_location (location)
  • 插入/更新时同步维护:Db::table('shops')->insert(['location' => Db::raw("POINT($lng, $lat)")])

注意:POINT 字段不能为 NULL,且 MySQL 的 ST_* 函数对 NULL 输入会返回 NULL,查不到结果也不报错——容易误判为“没数据”。

为什么用 Db::raw('ACOS(...)') 写 Haversine 总是不准

核心原因就两个:参数顺序反了、没转弧度。Haversine 公式里 COS 和 SIN 的输入必须是弧度,而数据库里的经纬度是角度。

典型翻车写法:

ACOS(SIN(lat1) * SIN(lat2) + COS(lat1) * COS(lat2) * COS(lng2 - lng1)) * 6371

正确写法(MySQL):

ACOS(
  SIN(RADIANS(lat1)) * SIN(RADIANS(lat2)) + 
  COS(RADIANS(lat1)) * COS(RADIANS(lat2)) * 
  COS(RADIANS(lng2 - lng1))
) * 6371

更稳妥的做法是直接用 ST_Distance_Sphere,它内部已处理好球面模型和单位转换,还支持 WGS84 坐标系校准——这点在跨省查询时误差能差几百米。

实际项目里,地理查询的瓶颈往往不在公式本身,而在坐标来源是否一致(比如前端用 GCJ-02,后端用 WGS-84)、缓存是否穿透、边界条件是否覆盖(海洋、国界、极地)。这些比选哪个函数重要得多。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2173

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1339

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

775

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

2972

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

5008

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

1139

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

5271

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

4642

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

6134

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程