【问题标题】:Hibernate persist failure with PostGIS GeometryPostGIS Geometry 的休眠持续失败
【发布时间】:2012-09-02 13:45:29
【问题描述】:

previous question 相关。我有一个 Spring Roo 应用程序,它使用 Hibernate 使用 JTS 将 Geometry 对象写入 PostGIS 数据库。我相信我已经解决了在定义 Geometry 对象时遇到的问题,现在 Hibernate 正在执行它的 persist() 方法,但是在它到达数据库之前出现了问题,我得到了下面的异常。

这里有一些有趣的行。首先来自 Hibernate 日志,要持久化的对象,然后是 SQL 查询(大概是 ? 被替换了):

...
DEBUG org.hibernate.pretty.Printer - com.test.LandUse{id=1, centerPoint=POINT (5 6), version=0}
...
DEBUG org.hibernate.SQL - insert into land_use (center_point, version, id) values (?, ?, ?)
...

然后发生了更多的事情,虽然没有明显的坏事。但是我没有看到任何“最终”SQL,并且尝试回滚事务。那么:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$afterReturning$org_springframework_transaction_aspectj_AbstractTransactionAspect$3$2a73e96c(AbstractTransactionAspect.aj:78)
    at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethod$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj:44)
    at com.test.LandUse.persist(LandUse.java:1)
    at com.test.LandUse_Roo_Jpa_ActiveRecord.ajc$interMethodDispatch1$com_test_LandUse_Roo_Jpa_ActiveRecord$com_test_LandUse$persist(LandUse_Roo_Jpa_ActiveRecord.aj)
    at com.test.LandUseController_Roo_Controller.ajc$interMethod$com_test_LandUseController_Roo_Controller$com_test_LandUseController$create(LandUseController_Roo_Controller.aj:29)
    at com.test.LandUseController.create(LandUseController.java:1)
...
Caused by: javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
    ... 54 more
Caused by: java.lang.UnsupportedOperationException
    at org.hibernate.spatial.GeometrySqlTypeDescriptor.getBinder(GeometrySqlTypeDescriptor.java:52)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278)
    at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:89)
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2430)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
    ... 55 more

我一直试图让这个简单的用例(一个只有一个几何属性的对象)工作了一个多星期,现在我已经束手无策了。如果我用 String 替换 Geometry 对象,它就可以正常工作。有谁知道什么可能导致这样的错误?

编辑:Thierry 下面的回答让我仔细研究了源代码,我注意到GeometrySqlTypeDescriptor 中抛出了异常,其中有一些有趣的内容:

/**
 * A generic <code>SqlTypeDescriptor</code>, intended to be remapped
 * by the spatial dialect.
 *
 * @author Karel Maesen, Geovise BVBA
 *         creation-date: 7/27/11
 */
public class GeometrySqlTypeDescriptor implements SqlTypeDescriptor {

    public static final GeometrySqlTypeDescriptor INSTANCE = new GeometrySqlTypeDescriptor();

    @Override
    public int getSqlType() {
        return 3000; //this value doesn't conflict with presently defined java.sql.Types values.
    }

    @Override
    public boolean canBeRemapped() {
        return true;
    }

    @Override
    public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
        throw new UnsupportedOperationException();
    }

    @Override
    public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
        throw new UnsupportedOperationException();
    }
}

特别是,请注意类注释表明 Hibernate 方言映射明显有问题。不幸的是,我不知道这意味着什么,但我猜是由于某种版本不匹配。 (另请注意 SQL 类型 3000 的声明,根据 my previous error!)

根据Hibernate Spatial usage guide,我当前的方言是org.hibernate.spatial.dialect.postgis.PostgisDialect。我正在使用 Hibernate Spatial 4.0-M1、JTS 1.12 和 PostGIS 2.0.1。我可能会尝试几个不同版本的 PostGIS,特别是因为这是 Hibernate Spatial 应该提供但似乎没有提供的一个依赖项。

【问题讨论】:

  • 我能够毫无怨言地删除 pom.xml 中对 postgis-jdbc 的依赖,所以大概 Hibernate Spatial 正在为我拖入正确的版本。但是问题仍然存在(哈哈)。

标签: spring hibernate persistence postgis rollback


【解决方案1】:

问题似乎是没有正确拾取和集成 PostgisDialect,因此不支持所需的操作。解决方案就像从 Hibernate 3.6.9.Final 升级到 4.1.6.Final 一样简单!

See my thread on the mailing list for more information.

根据该线程,您还应该知道,从 Hibernate Spatial 4.0-M1 开始,只有几何类型被指定为 Hibernate,因此 @Column 注释 必须 设置 columnDefinition="Geometry" , 和 not Point 或其他任何东西。将来可能会解决此问题。

有了这本修改集,我终于可以写一个指向数据库的点了!正确的属性规范是:

@Column(columnDefinition="Geometry")
@Type(type = "org.hibernate.spatial.GeometryType")
private Point centerPoint;

【讨论】:

  • 很高兴知道这一点!我认为它与Hibernate Migration Guide 3.6,第 4 部分)If you are using Hibernate 3.6.0 with PostgreSQL, the global environment variable, hibernate.jdbc.use_streams_for_binary, must be set to false if you are using clob or blob properties. In addition, using materialized_blob and materialized_clob properties with PostgreSQL is currently broken. See HHH-4617 for details (fixed in 3.6.1) 中的其他内容有关
  • 对于未来的其他读者:在将点打印到屏幕上并在将它们存储到数据库之前将点转换为几何时,解决方案是一个很好的解决方法,直到 Postgis 项目处理几何的子类型作为适当的休眠类型。如果有的话,也许你可以在 DAO 层中执行此操作。
  • 这个问答系列拯救了我的项目。非常感谢大家!
  • 太棒了!我不想让其他人不得不再次经历这一切。
  • @Travis:很抱歉,我不知道该怎么做。我什至不记得我自己做了什么。我建议在邮件列表(上面链接)上追踪问题,因为这些人知道他们的东西。
【解决方案2】:

当我忘记在休眠配置文件中添加 Postgis 方言时,我得到了这个异常。

将以下行添加到 hibernate.cfg.xml

<property name="dialect">org.hibernate.spatial.dialect.postgis.PostgisDialect</property>

【讨论】:

    【解决方案3】:

    是的,? 将替换为您需要存储的值。

    您是否尝试使用以下类型:GeometryUserType 而不是 GeometryType? 我怀疑 Hibernate Spatial Project 的 API 不直接支持 GeometryType。它可能是一个抽象类,您无法直接实例化它以使用注释映射您的数据 - 正如我们所试验的那样,它的作用超出了场景。

    Caused by: java.lang.UnsupportedOperationException 这让我知道了。

    the tutorial you have followed 中的最后一个 XML 内容很清楚:

    ...
    <property name="geometry" type="org.hibernatespatial.GeometryUserType">
        <column name="geom" />
    </property>
    ...
    

    查看GeometryUserType 中的代码,我只看到一处可能引发这些异常的地方。

    public Object conv2DBGeometry(Geometry jtsGeom, Connection connection) {
            org.postgis.Geometry geom = null;
            jtsGeom = forceEmptyToGeometryCollection(jtsGeom);
            if (jtsGeom instanceof com.vividsolutions.jts.geom.Point) {
                geom = convertJTSPoint((com.vividsolutions.jts.geom.Point) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.LineString) {
                geom = convertJTSLineString((com.vividsolutions.jts.geom.LineString) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiLineString) {
                geom = convertJTSMultiLineString((com.vividsolutions.jts.geom.MultiLineString) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.Polygon) {
                geom = convertJTSPolygon((com.vividsolutions.jts.geom.Polygon) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPoint) {
                geom = convertJTSMultiPoint((com.vividsolutions.jts.geom.MultiPoint) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.MultiPolygon) {
                geom = convertJTSMultiPolygon((com.vividsolutions.jts.geom.MultiPolygon) jtsGeom);
            } else if (jtsGeom instanceof com.vividsolutions.jts.geom.GeometryCollection) {
                geom = convertJTSGeometryCollection((com.vividsolutions.jts.geom.GeometryCollection) jtsGeom);
            }
    
            if (geom != null)
                return new PGgeometry(geom);
            else
                throw new UnsupportedOperationException("Conversion of "
                        + jtsGeom.getClass().getSimpleName()
                        + " to PGgeometry not supported");
        }
    

    我认为 PGgeometry 代表 PostGis Geometry(或者可能是 PostgreSQL)。

    我发现 Karel Maesen 和其他人谈论 InnoDB 支持不太好的一些主题,但它们可能已经过时 (05-2011)。

    祝你好运!

    【讨论】:

    • 我的理解是 GeometryUserType 是 Hibernate Spatial 1.0 的正确类型,它已被 GeometryType Hibernate Spatial 4.0 取代。 org.hibernate.spatial.GeometryUserType 在 4.0 中不存在。最接近的替代方案是 org.hibernate.spatial.GeometrySqlTypeDescriptor,但不出所料,它也失败了。
    • 好的,不记得这些信息了。很好的收获。
    • 但它确实引出了一些有趣的观点!请参阅已编辑的问题。
    • 我看过了。它似乎让我们扭转了局面,但什么也没解决……我建议您阅读 official forum 上的帮助或通过他们的邮件列表系统寻求帮助。
    • 谢谢蒂埃里,你是个传奇人物。我现在只是打邮件列表。也许我最大的弱点是总是等待太久才寻求帮助:)。
    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多