使用Hibernate Spatial Criteria查询圆形范围车辆点数据遇问题
解决Hibernate Spatial Criteria查询MySQL Point类型的距离范围问题
首先得说清楚你遇到的问题根源:你用的Hibernate Spatial 4.3版本里,MySQLSpatial56Dialect并没有实现dwithin函数的适配——SpatialRestrictions.distanceWithin是基于OGC标准的空间函数设计的,但MySQL的空间函数命名和逻辑和标准有差异,所以直接调用就会抛出那个不支持的异常。
既然原生SQL里ST_Distance_Sphere是有效的,那我们可以绕开通用的SpatialRestrictions,直接在Criteria里调用MySQL的原生函数,具体做法如下:
步骤1:修正坐标顺序(很重要!)
首先注意:JTS的Coordinate构造器是经度在前,纬度在后,你之前写的new Coordinate(latitude,longitude)是反的,这会导致查询的中心点完全错误,一定要改过来!
步骤2:用SQLRestriction实现范围查询
直接在Criteria中添加原生SQL限制条件,调用ST_Distance_Sphere函数,代码如下:
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.io.WKTWriter; import org.hibernate.criterion.Restrictions; import org.hibernate.type.StandardBasicTypes; // 正确创建中心点:经度在前,纬度在后 final Point circleCenterPoint = new GeometryFactory().createPoint(new Coordinate(longitude, latitude)); // 把Point转成WKT格式字符串,方便MySQL解析 String centerWkt = new WKTWriter().write(circleCenterPoint); // 把公里半径转成米,因为ST_Distance_Sphere返回的是米单位 double radiusInMeters = radiusInKm * 1000; // 添加SQL限制条件 criteria.add(Restrictions.sqlRestriction( "ST_Distance_Sphere(location, ST_GeomFromText(?)) <= ?", new Object[]{centerWkt, radiusInMeters}, new Type[]{StandardBasicTypes.STRING, StandardBasicTypes.DOUBLE} ));
为什么这个方法可行?
ST_GeomFromText(?)会把WKT格式的Point字符串转换成MySQL能识别的Point类型,和你数据库里的location字段类型匹配ST_Distance_Sphere会计算两个Point之间的球面距离(单位是米),直接和我们转换后的半径比较就能筛选出范围内的车辆
额外注意事项
- 你的实体类定义是正确的:
@Type(type="org.hibernate.spatial.GeometryType") @Column(name = "location", columnDefinition="Point"),保持这个配置就行 - 确认你的MySQL版本是5.6及以上,因为
ST_Distance_Sphere是从MySQL5.6开始支持的,刚好匹配你用的MySQLSpatial56Dialect
内容的提问来源于stack exchange,提问作者user3529850
相关产品推荐
相关产品推荐

