【问题标题】:Jhipster-generated Spring Boot + MySql project config for spatial queries用于空间查询的 Jhipster 生成的 Spring Boot + MySql 项目配置
【发布时间】:2021-08-13 00:56:50
【问题描述】:

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

有许多帖子和指南解决了这个问题,但它们并没有为我解决问题。我遵循了教程here、有用的文档here,并尝试了post 1post 2post 3post 4 和其他几个中的解决方案/建议。我还将我的代码与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 文件的上述部分无效。

【问题讨论】:

    标签: mysql spring-boot jhipster h2 hibernate-spatial


    【解决方案1】:

    我经历了空间 Postgresql 的这条路,然后很痛苦:直到我们决定放弃 H2,CI 才发现错误。

    我建议您使用 docker 和 testcontainers 在 dev 和 prod 中使用相同的数据库,JHipster 支持这一点,但您自己也很容易做到。

    【讨论】:

    • 确实,我们可能不得不为此使用 docker,但我希望保留 H2 并找到一些能够与它一起使用的空间查询方言,就像它与我们的 prod db 一样。但是如果你的经历也这么痛苦,如果问题不断出现,那么这条路可能是死路一条。在 H2 和我们真正的 prod 数据库之间的不匹配方面,我已经遇到了其他奇怪的问题,所以 H2 的便利性可能不值得。
    【解决方案2】:

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

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

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2018-03-05
      • 1970-01-01
      • 2017-02-05
      • 1970-01-01
      • 2014-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多