【问题标题】:Hibernate Exception on MySQL Cross Join QueryMySQL 交叉联接查询上的休眠异常
【发布时间】:2011-11-06 23:24:39
【问题描述】:

我正在尝试批量删除对象 Feature,该对象与另一个类 FeaturesMetadata 具有双向多对一关系。我抛出了一个 SQLGrammerException。

我正在使用的 hql:

String hql = "delete from Feature F where F.featuresMetadata.stateGeoId = :stateGeoId";

开启show SQL,生成如下:

 delete from FEATURE cross join FEATURESMETADATA featuresme1_ where STATEGEOID=?

直接在 db 客户端中运行 SQL 会出现此异常:

 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'cross join FEATURESMETADATA featuresme1_ where stategeoid='01'' at line 1

由于生成的 SQL 抛出异常,我尝试将方言从 MySQL5InnoDBDialect 更改为 MySQLInnoDBDialect,但没有任何变化。

有人可以帮忙吗?

【问题讨论】:

  • FeaturesMetaData 是否有 FK to Feature?
  • Feature 对 FeaturesMetadata 有一个 FK。

标签: mysql hibernate


【解决方案1】:

您可能在此类 HQL 查询中没有联接。引用自reference documentation

不能在批量 HQL 中指定任何隐式或显式连接 询问。子查询可以用在 where 子句中,其中 子查询本身可能包含连接。

所以我想这样的事情应该可以工作:

delete from Feature F where F.id in 
    (select f2.id from Feature f2 where f2.featuresMetadata.stateGeoId = :stateGeoId)

【讨论】:

  • 噢!我已经读了好几遍了,仍然没有点击。已接受答案。
  • 嗨,我很惊讶它对你有用,因为我得到:org.hibernate.exception.GenericJDBCException:你不能在 FROM 子句中指定目标表“用户”进行更新。发生这种情况是因为您无法修改在 SELECT 部分中使用的同一个表(在您的情况下是 Feature 表)。此行为记录在:dev.mysql.com/doc/refman/5.6/en/update.html。有什么建议吗?
  • 哇。我认为 HQL 是关于使查询比 SQL 更简化和面向对象。我不明白为什么 Hibernate 不能自己弄清楚如何在没有显式连接的情况下将对象之间的关系转换为 SQL 查询。
  • 无法理解这是如何回答主要问题的:在 HQL 中,他没有进行任何加入...
  • @Phate 他在做一个 implicit 连接,你可以看到 Hibernate 将查询转换为交叉连接。
【解决方案2】:

我遇到了同样的问题,并努力寻找一个合理的答案。看来,即使您采用这种方法,生成的 SQL 也是非常低效的(根据我的阅读)。

于是我退后一步,做了以下事情:

    List<Properties> props = propDao.findPropertiesByHotelCode(hotel.getCode());
    propDao.deleteInBatch(props);
    propDao.flush();

基本上宁可尝试“删除位置”,我正在选择位置,然后批量删除我检索到的集合。

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    这确实是从Hibernate相当差。但是你可以在 repo 中这样解决它:(至少在 PostgreSQL 中,不确定是否应该为 MySql 修改此语法)

    @Modifying
    @Query(nativeQuery = true, value = """
        DELETE FROM feature f
        USING features_metadata fd
        WHERE f.features_metadata_id = fd.id AND fd.state_geo_id = :stateGeoId
        """)
    void deleteByStateGeoIdId(@Param("stateGeoId") UUID stateGeoId);
    

    【讨论】:

      猜你喜欢
      • 2014-08-08
      • 2014-08-22
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      相关资源
      最近更新 更多