Jhipster 生成的 Spring Boot + MySql 空间查询的项目配置

Jhipster-generated Spring Boot + MySql project config for spatial queries

我的目标是将地理空间查询的功能添加到我的 jhipster 生成的 Spring Boot + MySql 项目中,但是我未能正确配置我的 H2 数据库以用于我的测试执行的查询并通过我的开发数据库进行应用程序的本地部署。由于我们有严格的 CI/CD 管道,这意味着我还无法在产品中进行测试,但我怀疑我也会 运行 陷入同样的​​错误。在测试或开发环境中执行空间查询时出现的错误:org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "WITHIN" not found;.

有很多帖子和指南解决了这个问题,但它们都没有解决我的问题。我已按照教程 here, the helpful documentation here, and have tried the solutions/suggestions in , post 2, post 3, , and several others. I also compared my code to this example project 进行操作。但是我仍然无法克服这个错误。

相关配置... pom.xml:

...
<java.version>1.8</java.version>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
<spring.version>5.1.8.RELEASE</spring.version>
<hibernate.version>5.3.10.Final</hibernate.version>
<h2.version>1.4.199</h2.version>
<jts.version>1.13</jts.version>
...
    <repositories>
        <repository>
            <id>OSGEO GeoTools repo</id>
            <url>http://download.osgeo.org/webdav/geotools</url>
        </repository>
        <repository>
            <id>Hibernate Spatial repo</id>
            <url>http://www.hibernatespatial.org/repository</url>
        </repository>
    </repositories>
...
<dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-spatial</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vividsolutions</groupId>
            <artifactId>jts</artifactId>
            <version>${jts.version}</version>
        </dependency>
</dependencies>

我的主要application.yml:

spring:
  jpa:
    open-in-view: false
    properties:
      hibernate.jdbc.time_zone: UTC
    hibernate:
      dialect: org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect
      ddl-auto: none

我的 application-dev.yml 我的开发环境:

spring:
  h2:
    console:
      enabled: false
  jpa:
    database-platform: org.hibernate.spatial.dialect.h2geodb.GeoDBDialect
    database: H2
    show-sql: true
    hibernate:
      dialect: org.hibernate.spatial.dialect.h2geodb.GeoDBDialect

我的 application-prod.yml 产品:

spring:
  jpa:
    database-platform: org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect
    database: MYSQL
    show-sql: false

我的test/application.yml:

spring:
  jpa:
    database-platform: org.hibernate.spatial.dialect.h2geodb.GeoDBDialect
    database: H2
    open-in-view: false
    show-sql: false
    hibernate:
      dialect: org.hibernate.spatial.dialect.h2geodb.GeoDBDialect
      ddl-auto: none

服务层相关代码:

    @Override
    @Transactional(readOnly = true)
    public Page<MyObject> findAllWithinDistanceOfLocation(Float distance, Point location, Pageable pageable) {
        log.debug("Request to get all MyObject within a distance centered on location");
        GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
        shapeFactory.setNumPoints(32); // 32 = number of points to define circle. Default is 100. Higher the number, the more accurately drawn the circle
        shapeFactory.setCentre(location.getCoordinate());
        shapeFactory.setSize(distance * 2);
        Geometry areaOfInterest = shapeFactory.createCircle();
        return myObjectRepository.findAllWithinCircle(areaOfInterest, pageable);
    }

存储库中的相关代码:

@Query("select e from MyObjectTable e where within(e.location, :areaOfInterest) = true")
    Page<MyObject> findAllWithinCircle(@Param("areaOfInterest") Geometry areaOfInterest, Pageable pageable);

数据库配置bean中的相关代码:

/**
     * Open the TCP port for the H2 database, so it is available remotely.
     *
     * @return the H2 database TCP server.
     * @throws SQLException if the server failed to start.
     */
    @Bean(initMethod = "start", destroyMethod = "stop")
    @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
    public Object h2TCPServer() throws SQLException {
        String port = getValidPortForH2();
        log.debug("H2 database is available on port {}", port);
        return H2ConfigurationHelper.createServer(port);
    }

    private String getValidPortForH2() {
        int port = Integer.parseInt(env.getProperty("server.port"));
        if (port < 10000) {
            port = 10000 + port;
        } else {
            if (port < 63536) {
                port = port + 2000;
            } else {
                port = port - 2000;
            }
        }
        return String.valueOf(port);
    }

我已经为上面的属性尝试了不同的值,试图以基于文档和其他项目的原则方式这样做,但我似乎无法让它正常工作。我怀疑我缺少一个为 WITHIN 创建别名的 h2 初始配置命令,但仍然无法理解它并使其正常工作。

注意:我已经包含和排除了 pom 文件的上述部分,但没有任何效果。

我经历了空间 Postgresql 的这条道路,然后很痛苦:CI 在我们决定放弃 H2 之前没有发现错误。

我建议您在开发和生产中使用相同的数据库,使用 docker 和测试容器,JHipster 支持这一点,但您自己也很容易做到。

对于那些想知道我们如何解决这个问题的人...

问题:我们的 Heroku CI/CD 管道不支持测试容器,如下所述:https://devcenter.heroku.com/articles/heroku-ci#docker-deploys

引用文档:“目前,无法使用 Heroku CI 来测试容器构建。”

使这个问题更加复杂的是,H2 对空间查询的支持问题太多,并且给出的结果与本地 MySql 数据库不同,并造成了原始 post 中概述的无数与方言相关的问题。

不理想但可行的解决方案:是开发过程“解决方法”与一些标准测试实践的结合。

首先,我们创建了一个测试容器配置文件,当使用该测试容器配置文件执行 ./mvnw verify 时,它将 运行 地理空间集成测试。 Heroku CI/CD 管道没有 运行 地理空间集成测试,但我们将其作为我们“完成定义”的一部分,以 运行 在本地进行这些测试。

为了使这种情况不那么糟糕和容易出错,我们采用了典型的单元测试策略:模拟使用地理空间查询的存储库,并在单元测试中执行业务逻辑。 CI/CD 管道中的这些 运行。

下一步是将 CI/CD 管道迁移到支持容器的管道。但与此同时,上述方法为我们提供了足够的重叠覆盖范围,让我们有信心将基于地理空间的功能推广到产品中。在对功能增强和扩展进行了几个月的压力测试之后,到目前为止,从产品的角度来看,一切似乎都运行良好。