我有一个Spring Roo + Hibernate项目,该项目从客户端应用程序获取JTS已知文本(WKT(字符串输入,将其转换为JTS Geometry对象,然后尝试将其写入PostGIS数据库。我在JDBC连接和类型方面遇到了一些问题,但这些问题似乎已经通过以下方式解决了:
@Column(columnDefinition = "Geometry", nullable = true)
private Geometry centerPoint;
转换确实:
Geometry geom = new WKTReader(new GeometryFactory(new PrecisionModel(), 4326)).read(source);
但是现在,当Hibernate尝试将我的几何对象写入数据库时,我收到一个错误:
2012-08-31 21:44:14,096 [tomcat-http--18] ERROR org.hibernate.util.JDBCExceptionReporter - Batch entry 0 insert into land_use (center_point, version, id) values ('<stream of 1152 bytes>', '0', '1') was aborted. Call getNextException to see the cause.
2012-08-31 21:44:14,096 [tomcat-http--18] ERROR org.hibernate.util.JDBCExceptionReporter - ERROR: Invalid endian flag value encountered.
很明显,该错误与二进制表示有关,二进制表示可能是作为具有一定字节序的众所周知的二进制(WKB(生成的。然而,由于Hibernate隐藏了所有的坚持,我真的无法判断事情的发展方向。
我已经与几何学的东西斗争了好几天,关于这些错误的信息很少,所以有人有什么好主意吗?我可以在某处指定字节序(休眠或 PostGIS(,或者以不同的格式 (WKT( 存储吗?
编辑:我还应该提到,我正在使用最新的一切,它通常似乎是兼容的:
- 春季 3.1.1, Roo 1.2.1
- 休眠 3.6.9
- 休眠空间 4.0-M1
- JTS 1.12
- PostgreSQL 9.1
- Postgis-JDBC 1.5.3(不是最新的,但建议用于休眠空间,从源代码编译(
- postgis-jdbc 2.0.1(现在刚刚尝试了这个以匹配PostgreSQL安装的版本,同样的问题(
Hibernate Spatial 4 教程建议我将属性注释设置为:
@Type(type="org.hibernate.spatial.GeometryType")
private Geometry centerPoint;
。但是当我这样做时,我得到了另一个错误,当前注释解决了这个错误。
我解决了这个问题,将这一行添加到"应用程序属性"中:
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect
解决方案似乎如下:
@Column
将字段映射到带有 JPA 注释
的所需列 @Type
指定与方言的休眠映射。
@Column(columnDefinition = "Geometry", nullable = true)
@Type(type = "org.hibernate.spatial.GeometryType")
public Point centerPoint;
您可以在 hibernate .cfg.xml 文件中添加 Hibernate 属性以查看 db 请求,并尝试使用带有"UTF-8"/"ANSI"/"其他字符集"的基于文本的编辑器(如 Notepad++(捕获字符串编码问题
<!--hibernate.cfg.xml -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="use_sql_comments">true</property>
要添加休眠属性,您将拥有一个包含以下内容的休眠.cfg.xml文件。不要复制/粘贴它,因为它是面向MySQL的。看看我之前插入
的属性的位置。 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">true</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">db-password</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db-name</property>
<property name="hibernate.connection.username">db-username</property>
<property name="hibernate.default_entity_mode">pojo</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.search.autoregister_listeners">false</property>
**<property name="hibernate.show_sql">true</property>**
<property name="hibernate.use_sql_comments">false</property>
<mapping ressource="...." />
<!-- other hbm.xml mappings below... -->
</session-factory>
</hibernate-configuration>
记录所有sql的另一种方法是在log4j.properties文件中添加特定于包的属性:
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE
祝你好运!
pilladooo的解决方案适用于Spring boot 2.0.3,hibernate/spatial 5.2.17.Final,Postgres 9.5。
在我的例子中,实体中的列定义为@Column(名称 = "几何"(私有几何几何;
并在数据库中作为类型"几何"(以避免休眠自动生成的bytea类型(
首先,我通过添加 columnDefinition = "geometry" 解决了"遇到无效的字节序标志值",但之后休眠将无法通过模式验证"模式验证:在表 [my_shema.my_geometry_table] 的列 [geometry] 中遇到错误的列类型;找到了[几何(类型#其他(],但期待[bytea(类型#VARBINARY(]">
添加spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisDialect后,它终于起作用了。ColumnDefinition 现在也是多余的
请参阅,http://trac.osgeo.org/postgis/ticket/1830 在 Postgresql 9xx 和 Postgis 2xx 出现时出现了一个问题,在使用 postgres 实用程序 pgsql2shp 时,它导致了相同的"无效的字节序标志"错误。可以通过删除旧版本的库 libpq.so 来修复它,因为它是由于 Postgres 更改了 bytea 的默认行为。
对于那些仍在为这个问题苦苦挣扎的人,我已经为此苦苦挣扎了好几天,事实证明我的问题是,我使用了错误的软件包。com.vividsolutions
的几何形状已移至org.locationtech
。所以你应该宁愿使用org.locationtech
.Maven 说
我让它使用以下配置。我正在使用Spring Boot 2.5.1,PostGIS和hibernate-spatial 5.4.32.Final。几个关键点:
- 我使用的点类是org.locationtech.jts.geom.Point
- 您不需要特殊的注释。这是我的实体类。
实体:
@Enity public class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Point location;
}
同样在应用程序属性中,我使用
spring.jpa.database-platform=org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect
然后在服务类中,我可以通过如下调用将对象保存到数据库中。
public Vehicle createVehicle(String name, Double longitude, Double latitude) {
GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);
var point = geometryFactory.createPoint(new Coordinate(longitude, latitude));
var vehicle = new Vehicle(name, point);
return vehicleRepository.save(vehicle);
}
在与给定的问题进行了一些斗争之后,这里有一些步骤可以帮助我解决它。首先,我应该提到我正在使用WildFly 17服务器,PostgreSQL 12和PostGIS 3.0.0。现在我认为在这个问题上很重要的步骤:
在META-INF
中制作jboss-deployment-structure.xml
文件(如果您没有(,并排除 WildFly 附带的休眠
<jboss-deployment-structure>
<deployment>
<exclusions>
<module name="org.hibernate" />
</exclusions>
</deployment>
</jboss-deployment-structure>
在pom.xml
中添加依赖项
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.12.Final</version>
</dependency>
和
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.4.12.Final</version>
</dependency>
确保休眠核心和休眠空间具有相同的版本(使用您喜欢的任何版本(。
您的persistence.xml
应该有财产
<property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisDialect"/>
最后,我认为这不是很重要,但我在Java中使用了org.locationtech.jts
几何。
我希望我没有跳过任何重要的事情,这些是必需的步骤。可能还有其他东西,但是尝试不同的解决方案已经过去了几个小时,我可能忘记包含一些依赖项/属性。答案是基于个人经验,因此请随时发表评论,证明我错了或扩展答案。无论如何,我希望有人会发现这个答案有用。