1. 소개
이 기사에서 우리는 Hibernate, hibernate-spatial 의 공간 확장을 살펴볼 것 입니다.
버전 5부터 Hibernate Spatial은 지리 데이터 작업을위한 표준 인터페이스를 제공합니다 .
2. Hibernate Spatial에 대한 배경
지리 데이터에는 Point, Line, Polygon 과 같은 엔티티 표현이 포함됩니다 . 이러한 데이터 유형은 JDBC 사양의 일부가 아니므로 JTS (JTS Topology Suite) 는 공간 데이터 유형을 나타내는 표준이되었습니다.
JTS 외에도 Hibernate 공간은 Geolatte-geom ( JTS에서 사용할 수없는 일부 기능이있는 최신 라이브러리) 도 지원합니다 .
두 라이브러리는 이미 hibernate-spatial 프로젝트에 포함되어 있습니다. 한 라이브러리를 다른 라이브러리보다 사용하는 것은 단순히 데이터 유형을 가져 오는 jar에 대한 질문입니다.
Hibernate 공간은 Oracle, MySQL, PostgreSQLql / PostGIS 및 기타 몇 가지 다른 데이터베이스와 같은 다른 데이터베이스를 지원하지만 데이터베이스 특정 기능에 대한 지원은 균일하지 않습니다.
hibernate가 주어진 데이터베이스에 대한 지원을 제공하는 함수 List을 확인하려면 최신 Hibernate 문서를 참조하는 것이 좋습니다.
이 기사에서는 MySQL의 전체 기능을 유지하는 인 메모리 Mariadb4j를 사용합니다 .
Mariadb4j 및 MySql의 구성은 비슷하며 mysql-connector 라이브러리도이 두 데이터베이스 모두에서 작동합니다.
3 . Maven 의존성
간단한 최대 절전 공간 프로젝트를 설정하는 데 필요한 Maven 의존성을 살펴 보겠습니다.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.12.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.12.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>ch.vorburger.mariaDB4j</groupId>
<artifactId>mariaDB4j</artifactId>
<version>2.2.3</version>
</dependency>
절전 공간적 의존성은 공간 데이터 유형에 대한 지원을 제공하는 것입니다. 최신 버전의 hibernate-core , hibernate-spatial , mysql-connector-java 및 mariaDB4j 는 Maven Central에서 얻을 수 있습니다.
4. Hibernate Spatial 설정
첫 번째 단계는 만드는 것입니다 hibernate.properties 에서 자원 디렉토리를 :
hibernate.dialect=org.hibernate.spatial.dialect.mysql.MySQL56SpatialDialect
// ...
hibernate-spatial과 관련된 유일한 것은 MySQL56SpatialDialect dialect 입니다. 이 방언은 MySQL55Dialect 방언을 확장하고 공간 데이터 유형과 관련된 추가 기능을 제공합니다.
속성 파일로드, SessionFactory 생성 및 Mariadb4j 인스턴스 인스턴스화에 특정한 코드 는 표준 최대 절전 모드 프로젝트에서와 동일합니다.
5 . 기하학 유형 이해
Geometry 는 JTS의 모든 공간 유형에 대한 기본 유형입니다. 이는 Point , Polygon 및 기타와 같은 다른 유형이 Geometry 에서 확장 됨을 의미합니다 . 형상 받는 자바 대응을 입력 형상 뿐만 아니라 MySQL을 입력합니다.
유형 의 문자열 표현을 구문 분석하여 Geometry 인스턴스를 얻습니다 . JTS에서 제공 하는 유틸리티 클래스 WKTReader를 사용하여 잘 알려진 텍스트 표현을 Geometry 유형 으로 변환 할 수 있습니다 .
public Geometry wktToGeometry(String wellKnownText)
throws ParseException {
return new WKTReader().read(wellKnownText);
}
이제이 메서드가 작동하는지 살펴 보겠습니다.
@Test
public void shouldConvertWktToGeometry() {
Geometry geometry = wktToGeometry("POINT (2 5)");
assertEquals("Point", geometry.getGeometryType());
assertTrue(geometry instanceof Point);
}
우리가 볼 수 있듯이, 메서드의 반환 형식이 경우에도 읽기 () 방법은 기하학은 실제 인스턴스가의 즉, 포인트 .
6. DB에 포인트 저장
이제 우리는 좋은 A를 어떤 아이디어가 있는지 형상 어떻게 얻을하는 유형이며, 포인트를 에서 문자열을 ,의를 살펴 보자 PointEntity를 :
@Entity
public class PointEntity {
@Id
@GeneratedValue
private Long id;
private Point point;
// standard getters and setters
}
엔티티 PointEntity 에는 공간 유형 Point 가 포함되어 있습니다 . 앞서 설명한 것처럼 Point 는 두 개의 좌표로 표시됩니다.
public void insertPoint(String point) {
PointEntity entity = new PointEntity();
entity.setPoint((Point) wktToGeometry(point));
session.persist(entity);
}
insertPoint () 메서드 는 Point 의 WKT (Well-Known Text) 표현 을 받아 Point 인스턴스 로 변환 하고 DB에 저장합니다.
다시 말해 , 세션 은 최대 절전 모드 공간에만 국한되지 않으며 다른 최대 절전 모드 프로젝트와 유사한 방식으로 생성됩니다.
여기서 Point 의 인스턴스가 생성되면 PointEntity 를 저장하는 프로세스가 일반 엔터티와 비슷하다는 것을 알 수 있습니다.
몇 가지 테스트를 살펴 보겠습니다.
@Test
public void shouldInsertAndSelectPoints() {
PointEntity entity = new PointEntity();
entity.setPoint((Point) wktToGeometry("POINT (1 1)"));
session.persist(entity);
PointEntity fromDb = session
.find(PointEntity.class, entity.getId());
assertEquals("POINT (1 1)", fromDb.getPoint().toString());
assertTrue(geometry instanceof Point);
}
호출 toString () A의 점은 a의 WKT 표현을 반환 포인트 . 이는 Geometry 클래스가 toString () 메서드를 재정의하고 이전에 보았던 WKTReader 의 보완 클래스 인 WKTWriter를 내부적으로 사용 하기 때문 입니다.
이 테스트를 실행하면 hibernate가 PointEntity 테이블을 생성 합니다.
해당 테이블을 살펴 보겠습니다.
desc PointEntity;
Field Type Null Key
id bigint(20) NO PRI
point geometry YES
예상대로 Type of Field Point 는 GEOMETRY 입니다. 이 때문에 SQL 편집기 (예 : MySql 워크 벤치)를 사용하여 데이터를 가져 오는 동안이 GEOMETRY 유형을 사람이 읽을 수있는 텍스트로 변환해야합니다.
select id, astext(point) from PointEntity;
id astext(point)
1 POINT(2 4)
그러나 Hibernate는 Geometry 또는 해당 하위 클래스에서 toString () 메서드를 호출 할 때 이미 WKT 표현을 반환하므로이 변환에 대해 신경 쓸 필요가 없습니다.
7. 공간 함수 사용
7.1. ST_WITHIN () 예제
이제 공간 데이터 유형으로 작동하는 데이터베이스 함수의 사용법을 살펴 보겠습니다.
MySQL의 이러한 함수 중 하나 는 한 Geometry 가 다른 Geometry 내에 있는지 여부를 알려주 는 ST_WITHIN () 입니다 . 여기에서 좋은 예는 주어진 반경 내의 모든 점을 찾는 것입니다.
서클을 만드는 방법부터 살펴 보겠습니다.
public Geometry createCircle(double x, double y, double radius) {
GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
shapeFactory.setNumPoints(32);
shapeFactory.setCentre(new Coordinate(x, y));
shapeFactory.setSize(radius * 2);
return shapeFactory.createCircle();
}
원은 setNumPoints () 메서드로 지정된 유한 한 점 집합으로 표시됩니다 . 반경은 호출하기 전에 두 배가됩니다 에는 setSize () 우리는 두 방향으로, 중심 주위에 원을 그릴 필요로하는 방법.
이제 앞으로 나아가서 주어진 반경 내에서 포인트를 가져 오는 방법을 살펴 보겠습니다.
@Test
public void shouldSelectAllPointsWithinRadius() throws ParseException {
insertPoint("POINT (1 1)");
insertPoint("POINT (1 2)");
insertPoint("POINT (3 4)");
insertPoint("POINT (5 6)");
Query query = session.createQuery("select p from PointEntity p where
within(p.point, :circle) = true", PointEntity.class);
query.setParameter("circle", createCircle(0.0, 0.0, 5));
assertThat(query.getResultList().stream()
.map(p -> ((PointEntity) p).getPoint().toString()))
.containsOnly("POINT (1 1)", "POINT (1 2)");
}
최대 절전 모드는 매핑 내 () 받는 기능을 ST_Within에 () 의 MySQL 기능.
여기서 흥미로운 관찰은 점 (3, 4)이 정확히 원 위에 있다는 것입니다. 그래도 쿼리는이 지점을 반환하지 않습니다. 때문이다 내 () 함수가 제공된 경우에만 true를 반환 기하학은 또 다른 내에서 완전히 기하학 .
7.2. ST_TOUCHES () 예제
여기에서는 데이터베이스 에 Polygon 집합을 삽입 하고 주어진 Polygon에 인접한 Polygon을 선택 하는 예제를 제공합니다 . PolygonEntity 클래스를 간단히 살펴 보겠습니다 .
@Entity
public class PolygonEntity {
@Id
@GeneratedValue
private Long id;
private Polygon polygon;
// standard getters and setters
}
이전 PointEntity 와 다른 점 은 Point 대신 Polygon 유형을 사용한다는 것 입니다.
이제 테스트로 이동해 보겠습니다.
@Test
public void shouldSelectAdjacentPolygons() throws 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("select p from PolygonEntity p
where touches(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())).containsOnly(
"POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))", "POLYGON ((3 0, 3 5, 8 5, 8 0, 3 0))");
}
insertPolygon () 메소드는 유사하다 에서 insertPoint () 우리가 이전에 보았던 방법. 소스에는이 메서드의 전체 구현이 포함되어 있습니다.
주어진 Polygon에 인접한 Polygon 을 찾기 위해 touches () 함수를 사용하고 있습니다. 분명히 주어진 Polygon에 닿는 가장자리가 없기 때문에 세 번째 Polygon 은 결과에 반환되지 않습니다 .
8. 결론
이 기사에서 우리는 hibernate-spatial이 저수준 세부 사항을 처리하기 때문에 공간 데이터 유형을 훨씬 더 간단하게 처리하는 것을 보았습니다.
이 기사에서는 Mariadb4j를 사용하지만 구성을 수정하지 않고도 MySql로 대체 할 수 있습니다.
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/hibernate-spatial
'Java' 카테고리의 다른 글
Spring 웹 애플리케이션의 Flash 속성 사용방법(예제) (0) | 2021.04.14 |
---|---|
Spring에서 HttpServletRequest를 여러 번 읽기 (0) | 2021.04.14 |
JPA를 사용한 저장 프로 시저 사용방법(예제) (0) | 2021.04.14 |
메모리 내 데이터베이스를 사용한 자체 포함 테스트 (0) | 2021.04.13 |
Spring을 사용한 JPA 사용방법(예제) (0) | 2021.04.13 |