Introduksjon til Hibernate Spatial

1. Introduksjon

I denne artikkelen ser vi på den romlige utvidelsen av dvalemodus, dvalemodus.

Starter med versjon 5, Hibernate Spatial gir et standard grensesnitt for arbeid med geografiske data.

2. Bakgrunn om dvalemodus

Geografiske data inkluderer representasjon av enheter som en Punkt, linje, polygon. Slike datatyper er ikke en del av JDBC-spesifikasjonen, og derfor har JTS (JTS Topology Suite) blitt en standard for å representere romlige datatyper.

Bortsett fra JTS, støtter Hibernate spatial også Geolatte-geom - et nylig bibliotek som har noen funksjoner som ikke er tilgjengelige i JTS.

Begge bibliotekene er allerede inkludert i dvalemodus-prosjektet. Å bruke ett bibliotek over et annet er ganske enkelt et spørsmål om fra hvilken krukke vi importerer datatyper.

Selv om Hibernate spatial støtter forskjellige databaser som Oracle, MySQL, PostgreSQLql / PostGIS og noen få andre, er ikke støtten for de databasespesifikke funksjonene ensartet.

Det er bedre å referere til den nyeste dvalemodusdokumentasjonen for å sjekke listen over funksjoner som dvalemodus gir støtte for en gitt database.

I denne artikkelen bruker vi Mariadb4j i minnet - som opprettholder den fulle funksjonaliteten til MySQL.

Konfigurasjonen for Mariadb4j og MySql er lik, selv mysql-connector-biblioteket fungerer for begge disse databasene.

3. Maven avhengigheter

La oss ta en titt på Maven-avhengighetene som kreves for å sette opp et enkelt dvale-romlig prosjekt:

 org. dvalemodus dvalekjerne 5.2.12.Final org. dvalemodus dvalemodus 5.2.12.Final mysql mysql-connector-java 6.0.6 ch.vorburger.mariaDB4j mariaDB4j 2.2.3 

De dvale-romlig avhengighet er den som vil gi støtte til de geografiske datatypene. De siste versjonene av dvalemodus, dvalemodus, mysql-connector-java og mariaDB4j kan fås fra Maven Central.

4. Konfigurere dvalemodus

Det første trinnet er å lage en dvalemodus. eiendommer i ressurser katalog:

hibernate.dialect = org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect // ...

Det eneste som er spesifikt for dvalemodus er MySQL56SpatialDialect dialekt. Denne dialekten utvider MySQL55Dialect dialekt og gir tilleggsfunksjonalitet knyttet til geodatatypene.

Koden som er spesifikk for å laste eiendomsfilen, og opprette en SessionFactory, og å sette i gang en Mariadb4j-forekomst, er det samme som i et standard dvaleprosjekt.

5. Forstå Geometri Type

Geometri er basistypen for alle romlige typene i JTS. Dette betyr at andre typer som Punkt, Polygon, og andre strekker seg fra Geometri. De Geometri skriv inn java tilsvarer GEOMETRI skriv inn MySql også.

Ved å analysere en String representasjon av typen, får vi en forekomst av Geometri. En bruksklasse WKTReader levert av JTS kan brukes til å konvertere enhver kjent tekstrepresentasjon til en Geometri type:

public Geometry wktToGeometry (String wellKnownText) kaster ParseException {returner ny WKTReader (). les (wellKnownText); }

La oss nå se denne metoden i aksjon:

@Test offentlig ugyldighet børConvertWktToGeometry () {Geometry geometry = wktToGeometry ("POINT (2 5)"); assertEquals ("Point", geometry.getGeometryType ()); assertTrue (geometry instance of Point); }

Som vi kan se, selv om returtypen til metoden er lese() metoden er Geometri, er den faktiske forekomsten av en Punkt.

6. Lagre et punkt i DB

Nå som vi har en god ide om hva en Geometri typen er og hvordan du får en Punkt ut av en String, la oss ta en titt på PointEntity:

@Entity offentlig klasse PointEntity {@Id @GeneratedValue private Lang id; privat punkt punkt; // standard getters og setters}

Merk at enheten PointEntity inneholder en romlig type Punkt. Som vist tidligere, a Punkt er representert av to koordinater:

public void insertPoint (String point) {PointEntity entity = new PointEntity (); entity.setPoint ((Point) wktToGeometry (point)); session.persist (enhet); }

Metoden insertPoint () aksepterer en kjent tekst (WKT) representasjon av en Punkt, konverterer den til en Punkt forekomst, og lagrer i DB.

Som en påminnelse er den økt er ikke spesifikk for dvalemodus og er opprettet på en måte som ligner på et annet dvaleprosjekt.

Vi kan merke her at når vi først har en forekomst av Punkt opprettet, prosessen med lagring PointEntity ligner på en hvilken som helst vanlig enhet.

La oss se på noen tester:

@Test offentlig ugyldig shouldInsertAndSelectPoints () {PointEntity entity = new PointEntity (); entity.setPoint ((Point) wktToGeometry ("POINT (1 1)")); session.persist (enhet); PointEntity fromDb = session .find (PointEntity.class, entity.getId ()); assertEquals ("POINT (1 1)", fromDb.getPoint (). toString ()); assertTrue (geometry instance of Point); }

Ringer toString () på en Punkt returnerer WKT-representasjonen av a Punkt. Dette er fordi Geometri klasse overstyrer toString () metode og internt bruk WKTWriter, en gratis klasse til WKTReader som vi så tidligere.

Når vi har kjørt denne testen, vil dvalemodus opprette PointEntity bord for oss.

La oss ta en titt på tabellen:

desc PointEntity; Feltype Null Nøkkel-ID bigint (20) NO PRI-punktgeometri JA

Som forventet, Type av FeltPunkt er GEOMETRI. På grunn av dette må vi konvertere denne GEOMETRY-typen til menneskelig lesbar tekst mens vi henter dataene ved hjelp av vår SQL-editor (som MySql-arbeidsbenk):

velg id, astext (punkt) fra PointEntity; id astext (punkt) 1 PUNKT (2 4)

Som dvalemodus returnerer imidlertid WKT-representasjon allerede når vi ringer toString () metode på Geometri eller noen av underklassene, trenger vi ikke bry oss om denne konverteringen.

7. Bruke romlige funksjoner

7.1. ST_WITHIN () Eksempel

Vi ser nå på bruken av databasefunksjoner som fungerer med romlige datatyper.

En av slike funksjoner i MySQL er ST_WITHIN () det forteller om en Geometri er innenfor en annen. Et godt eksempel her ville være å finne ut alle punktene innenfor en gitt radius.

La oss begynne med å se på hvordan du lager en sirkel:

public Geometry createCircle (dobbel x, dobbel y, dobbel radius) {GeometricShapeFactory shapeFactory = ny GeometricShapeFactory (); shapeFactory.setNumPoints (32); shapeFactory.setCentre (ny koordinat (x, y)); shapeFactory.setSize (radius * 2); returner formFabrikk.createCircle (); }

En sirkel er representert med et endelig sett med punkter spesifisert av setNumPoints () metode. De radius blir doblet før du ringer setSize () metode da vi trenger å tegne sirkelen rundt sentrum, i begge retninger.

La oss nå gå videre og se hvordan du henter poengene innenfor en gitt radius:

@Test offentlig tomrom skalSelectAllPointsWithinRadius () kaster ParseException {insertPoint ("POINT (1 1)"); insertPoint ("PUNKT (1 2)"); insertPoint ("POINT (3 4)"); insertPoint ("POINT (5 6)"); Query query = session.createQuery ("velg p fra PointEntity p der innenfor (p.point,: sirkel) = true", PointEntity.class); query.setParameter ("sirkel", createCircle (0.0, 0.0, 5)); assertThat (query.getResultList (). stream () .map (p -> ((PointEntity) p) .getPoint (). toString ())) .containsOnly ("POINT (1 1)", "POINT (1 2) "); }

Dvalemodus kartlegger sin innenfor() funksjon til ST_WITHIN () funksjon av MySql.

En interessant observasjon her er at punktet (3, 4) faller nøyaktig på sirkelen. Fortsatt returnerer ikke spørringen dette punktet. Dette er fordi de innenfor() funksjonen returnerer bare sann hvis den gitte Geometri er helt innenfor en annen Geometri.

7.2. ST_TOUCHES () Eksempel

Her presenterer vi et eksempel som setter inn et sett med Polygons i databasen og velg Polygons som grenser til et gitt Polygon. La oss ta en rask titt på PolygonEnhet klasse:

@Entity offentlig klasse PolygonEntity {@Id @GeneratedValue private Lang id; privat polygon polygon; // standard getters og setters}

Det eneste som er forskjellig her fra forrige PointEntity er at vi bruker typen Polygon i stedet for Punkt.

La oss nå gå mot testen:

@Test public void shouldSelectAdjacentPolygons () kaster ParseException {insertPolygon ("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))"); insertPolygon ("POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0))"); insertPolygon ("POLYGON ((2 2, 3 1, 2 5, 4 3, 3 3, 2 2))"); Query query = session.createQuery ("velg p fra PolygonEntity p hvor berører (p.polygon,: polygon) = true", PolygonEntity.class); query.setParameter ("polygon", wktToGeometry ("POLYGON ((5 5, 5 10, 10 10, 10 5, 5 5)))); assertThat (query.getResultList (). stream () .map (p -> ((PolygonEntity) p) .getPolygon (). toString ())). inneholder Only ("POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0)) "," POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0)) "); }

De insertPolygon () metoden ligner på insertPoint () metoden som vi så tidligere. Kilden inneholder full implementering av denne metoden.

Vi bruker berører () funksjon for å finne Polygons ved siden av et gitt Polygon. Tydeligvis den tredje Polygon returneres ikke i resultatet ettersom det ikke er kant å berøre det gitte Polygon.

8. Konklusjon

I denne artikkelen har vi sett at dvale-romlig gjør håndtering av romlige datatyper mye enklere ettersom det tar vare på detaljene på lavt nivå.

Selv om denne artikkelen bruker Mariadb4j, kan vi erstatte den med MySql uten å endre noen konfigurasjon.

Som alltid kan hele kildekoden for denne artikkelen finnes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found