You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Hibernate-Spatial查询范围内实体时遇WITHIN函数未找到错误

解决Hibernate-Spatial中WITHIN函数找不到的问题

看起来你遇到的Function "WITHIN" not found错误,核心原因是实体映射的空间类型配置错误,导致Hibernate无法生成正确的SQL调用MySQL的空间函数,另外还有一些依赖和配置细节需要调整。下面一步步帮你解决:

1. 核心问题:空间字段映射错误

你的Address类中,location字段用了@EmbeddedLocation类(包含latlon两个Double字段),同时加了@Column(columnDefinition = "point")——这是冲突的:

  • @Embedded会把Locationlatlon映射成数据库中两个独立的列,而不是单个POINT类型的列
  • Hibernate-Spatial的WITHIN函数需要操作的是数据库空间类型字段(比如POINT),而不是两个普通数值列,这直接导致SQL生成错误,数据库无法识别WITHIN函数的用法

修正实体映射

修改Address类,直接使用Geometry类型存储位置,替代Location嵌入类:

@Entity
public class Address extends UUIDEntity2 implements HasEmailAddress, HasLocation {
    // 使用Hibernate-Spatial的GeometryType映射POINT类型字段
    @Type(type = "org.hibernate.spatial.GeometryType")
    @Column(columnDefinition = "POINT SRID 4326") // 指定SRID为WGS84坐标系
    private Geometry location;

    // 保留lat/lon的访问方法(可选)
    public Double getLat() {
        return location != null ? location.getCoordinate().y : null;
    }

    public Double getLon() {
        return location != null ? location.getCoordinate().x : null;
    }

    // 设置lat/lon的方法(可选)
    public void setLocationFromLatLon(Double lat, Double lon) {
        if (lat != null && lon != null) {
            this.location = new GeometryFactory(new PrecisionModel(), 4326)
                .createPoint(new Coordinate(lon, lat));
        }
    }

    // 标准getter/setter
    public Geometry getLocation() { return location; }
    public void setLocation(Geometry location) { this.location = location; }
}

同时Resource类的关联逻辑无需修改,只需确保后续查询时引用的是Geometry类型的字段即可。

2. 修正Repository查询语句

现在resource.address.location是标准的Geometry类型了,查询语句可以保持不变,但要确保Hibernate能正确解析:

public interface ResourceRepository extends ExtendedJpaRepository<Resource, String> {
    @Query(value = "select resource from Resource resource where within(resource.address.location, :circle) = true")
    List<Resource> test(@Param("circle") Geometry circle);
}

3. 确保依赖版本兼容

你的hibernate-entitymanager没有指定版本,可能和hibernate-spatial(5.2.12.Final)版本不匹配,导致方言或函数映射错误。统一版本:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.2.12.Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-spatial</artifactId>
    <version>5.2.12.Final</version>
</dependency>

4. 调整测试代码的Circle生成

确保生成的Circle带有正确的SRID(和数据库字段一致,这里用4326):

public Geometry createCircle(double x, double y, double radius) {
    // 指定SRID为4326(WGS84),和数据库字段匹配
    GeometricShapeFactory shapeFactory = new GeometricShapeFactory(
        new GeometryFactory(new PrecisionModel(), 4326)
    );
    shapeFactory.setNumPoints(32);
    shapeFactory.setCentre(new Coordinate(x, y));
    shapeFactory.setSize(radius * 2); // size是直径
    return shapeFactory.createCircle();
}

5. 验证数据库配置

  • 确保你的MySQL版本是5.6+(支持空间函数)
  • 确保address表的location字段是POINT SRID 4326类型,且表的存储引擎是InnoDB(MyISAM也支持,但InnoDB更推荐)

完成这些调整后,Hibernate会正确生成调用MySQLST_Within函数的SQL,就不会再出现找不到函数的错误了。

内容的提问来源于stack exchange,提问作者Chinmoy Acharjee

火山引擎 最新活动