Сгенерированная Jhipster конфигурация проекта Spring Boot + MySql для пространственных запросов

Моя цель — добавить возможность геопространственных запросов в мой проект Spring Boot + MySql, сгенерированный jhipster, но мне не удалось правильно настроить мою базу данных H2 для запросов, выполняемых моими тестами, и моей базой данных разработчиков для локального развертывания приложения. Поскольку у нас есть строгий конвейер CI/CD, это означает, что я еще не смог протестировать в prod, но подозреваю, что и там столкнусь с той же ошибкой. Ошибка, которую я получаю при выполнении пространственного запроса в тестовой среде или среде разработки: org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "WITHIN" not found;.

Есть несколько сообщений и руководств, посвященных этой проблеме, но они не решили проблему для меня. Я следовал руководству здесь, полезной документации здесь и попробовал решения/предложения в сообщение 1, пост 2, post 3, post 4 и некоторые другие. Я также сравнил свой код с этим примером проекта. Но я все еще не могу пройти мимо этой ошибки.

Соответствующая конфигурация... 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

My 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);

Соответствующий код в компоненте конфигурации базы данных:

/**
     * 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);
    }

Я пробовал разные значения для вышеперечисленных свойств, пытаясь сделать это принципиальным образом на основе документации и других проектов, но, похоже, я не могу заставить это работать должным образом. Я подозреваю, что мне не хватает команды начальной настройки h2, которая создает псевдоним для WITHIN, но до сих пор не смог ее найти и заставить это работать.

Примечание. Я включил и исключил указанный выше раздел файла pom безрезультатно.


person kingofswords    schedule 24.05.2021    source источник


Ответы (1)


Я прошел этот путь для пространственного Postgresql и тогда было больно: CI не ловил баги, пока мы не решили отказаться от H2.

Я бы порекомендовал вам использовать одну и ту же базу данных в dev и prod, используя docker и testcontainers, JHipster поддерживает это, но это также легко сделать самостоятельно.

person Gaël Marziou    schedule 26.05.2021
comment
Действительно, для этого нам, возможно, придется использовать docker, но я надеюсь сохранить H2 и найти какой-нибудь диалект с поддержкой пространственных запросов, который будет работать с ним так же, как с нашей prod db. Но если ваш опыт был таким же болезненным и если проблемы продолжали возникать, то этот путь может оказаться тупиковым. Я уже сталкивался с другими странностями с точки зрения несоответствия между H2 и нашей реальной базой данных prod, так что, возможно, удобство H2 того не стоит. - person kingofswords; 15.06.2021