【问题标题】:org.hibernate.ObjectNotFoundException: No row with the given identifier exists, but it DOESorg.hibernate.ObjectNotFoundException:不存在具有给定标识符的行,但确实存在
【发布时间】:2012-02-17 13:57:57
【问题描述】:

我遇到了一个无法修复的休眠问题。

设置:Java EE、网络应用、Hibernate 3.2、Tomcat 6、Struts 2。

基本上,我使用我的服务器逻辑(一个 struts 操作)持久化一个对象,然后尝试将该数据提取到下一页并显示它。

我在保存对象后检查了数据库,果然,我可以看到那里有所有数据的行。

但是当我尝试检索它时,我得到了这个:

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [msc.model.Picture#73]

为了让事情变得更加混乱,当我重新启动 Tomcat 并尝试访问同一个对象时,我没有收到错误 - Hibernate 发现该行很好。

如果我执行一些其他操作,Hibernate 也将能够看到该行 - 可能在数据库中到处添加一行,甚至不在同一张表上。

从这一切中我怀疑是 Hibernate 错误,但我是 Hibernate 新手,所以我可能错了。请帮忙!我用谷歌搜索并搜索无济于事。

这是我的 Hibernate 配置:

<?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.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/msc</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">-------</property>
        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">80</property>
        <property name="current_session_context_class">thread</property>
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
        <mapping resource="msc/model/Picture.hbm.xml"/>
        <mapping resource="msc/model/Comment.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

这是我的两个映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="msc.model.Picture" table="PICTURE">
    <id column="PICTURE_ID" name="id">
      <generator class="native"/>
    </id>
    <property name="story"/>
    <property name="email"/>
    <property name="category"/>
    <property name="state"/>
    <property name="ratings"/>
    <property name="views"/>
    <property name="timestamp"/>
    <property name="title"/>
    <property lazy="true" name="image" type="blob">
      <column name="IMAGE"/>
    </property>
    <property lazy="true" name="refinedImage" type="blob">
      <column name="REFINEDIMAGE"/>
    </property>
    <property lazy="true" name="thumbnail" type="blob">
      <column name="THUMBNAIL"/>
    </property>
    <bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
      <key column="PICTURE"/>
      <one-to-many class="msc.model.Comment"/>
    </bag>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="msc.model.User" table="USER">
    <id column="USER_ID" name="id">
      <generator class="native"/>
    </id>
    <property name="username"/>
    <property name="email"/>
    <bag cascade="save-update" lazy="true" name="pictures" table="PICTURE">
      <key column="USER"/>
      <one-to-many class="msc.model.Picture"/>
    </bag>
    <bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
      <key column="USER"/>
      <one-to-many class="msc.model.Comment"/>
    </bag>
  </class>
</hibernate-mapping>

如果您需要更多信息,请告诉我,我很乐意提供帮助。

(注意:这不是这个问题的重复,场景不一样"No row with the given identifier exists" although it DOES exist

编辑:根据要求,发布 Java 代码:

保存对象的代码

Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();

hib_ses.beginTransaction();

hib_ses.save(user);

hib_ses.getTransaction().commit(); 

显示数据的代码(本例中为图像)

public class ImageAction extends ActionSupport implements ServletResponseAware, SessionAware {

    private HttpServletResponse response;
    Map session;
    private Long id;
    private int thumbnail;
    private InputStream inputStream;

    @Override
    public String execute() throws Exception {
        response.setContentType("image/jpeg");
        Session hib_session = HibernateUtil.getSessionFactory().getCurrentSession();
        hib_session.beginTransaction();

        //what is the ID now?
        Picture pic = (Picture) hib_session.load(Picture.class, getId());

        if (thumbnail == 1) {
            inputStream = (ByteArrayInputStream) pic.getThumbnail().getBinaryStream();
        } else {
            inputStream = (ByteArrayInputStream) pic.getRefinedImage().getBinaryStream();
        }

        hib_session.close();
        return SUCCESS;
    }

【问题讨论】:

  • getId() 是做什么的? Picture 类的 @Id 属性是什么?
  • @GrzegorzGrzybek ID 属性显示在映射中,它只是一个列。
  • @NastyPasty 我也有同样的问题;您是否最终解决了这个问题,如果没有,您是如何解决的?

标签: java sql hibernate jakarta-ee


【解决方案1】:

发生这种情况是因为您插入了一些本应作为外键但未引用任何内容的内容。 检查您的数据库是否存在该键(即使它在其他表的数据库中)。

【讨论】:

  • 我确认,至少在我的情况下,这就是问题所在。
  • 检查非常重要,我的数据库有这个问题,如果我们没有意识到这个问题,我们就会停滞不前
  • 就我而言,它发生是因为我评论了 session.flush()。所以我试图保持一个在数据库中并不真正存在的实体(使用 java 生成的主键等)
【解决方案2】:

检查您的所有映射和数据库设置。当您的数据库显示 nullable="true" 时,您可能在外键关系中设置了一些 not-null="true"。第一个导致 INNER JOIN,第二个导致 LEFT JOIN。

将日志级别设置为 TRACE 以查看所有步骤并在检索对象时查找生成的 SQL。

【讨论】:

    【解决方案3】:

    在多对一关系中,如果找不到映射行,您需要告诉 Hibernate 需要做什么。您可以通过以下方式进行配置:

    Annotation:
    @NotFound(action = NotFoundAction.IGNORE)
    Mapping XML:
    <many-to-one name="user" column="user_id" class="com.xyz.User" cascade="save-update, evict" not-found="ignore"/>
    

    【讨论】:

    • @NonFound(action = NotFoundAction.IGNORE) 会将FetchTypeLAZY 切换到EAGER
    【解决方案4】:

    只需检查您的数据库 id 73 在您的特定表中是否可用

    【讨论】:

      【解决方案5】:

      好的,我将在这里抛出一个理论。会不会是您尝试在第一次事务提交之前加载图片?

      由于事务尚未提交,因此该行对您用于读取图片的事务不可见(取决于您拥有的事务隔离级别)。

      然后,由于hib_session.close() 不在finally 块内,它不会被执行,线程绑定的会话仍然会有一个打开的事务。随后的请求获得 same Hibernate 会话,具有相同的打开事务,并且您从它发出的 select 中获得相同的结果(同样,取决于事务隔离级别 - 请参阅 documentation here,特别是对于REPEATABLE_READ)。

      这也可以解释为什么flush() 稍微好一点,因为如果flush()commit() 发生得早,竞争条件发生的机会就更小了。

      我建议你尝试在 finally 块中关闭会话,看看后续请求的行为是否会发生变化。

      【讨论】:

      • 理论似乎很有希望,当我在我的代码中应用调试点时一切正常。这意味着休眠有时间提交事务(我认为)!
      【解决方案6】:

      我遇到了这个问题,这里是发生了什么以及我如何解决它。你很可能也有同样的事情发生。

      我有 POST 和 USER 对象。它们处于 OneToMany 关系(一个用户可以有很多帖子)。使其成为双向关系,它们也处于多对一关系(一篇帖子仅属于一位用户)。

      课后的样子

      @Entity
      @Table(name="Post")
      public class Post {
      
      @Id
      @GeneratedValue(strategy=GenerationType.TABLE)
      private long postId;
      private String title;
      private String body;
      
      @ManyToOne(fetch=FetchType.EAGER)
      @JoinColumn(name = "postUserId")
      private AutoUser autoUser;
      // getter and setters
      

      用户类是

      @Entity
      @Table(name = "AUTO_USER")
      public class AutoUser implements UserDetails {
      
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long autoUserId;
      
      @Column(name = "USERNAME")
      private String username;
      
      @OneToMany
      private List<Post> postList = new ArrayList<>();
        // getter and setters
      

      第一个表名是 Post 和 AUTO_USER 我有 3 个用户持久保存到 AUTO_USER 表(id​​ 为 1、2、3)。每个用户在 Post 表 1 中有 3 个条目。 (连接列或外键分别为 1、2、3)

      然后我只更改了用户对象的表名并将其命名为@Table(name = "AUTO_USER2")。 并且我在这个表中只有一个 id 为 1 的用户。

      在我的代码中,我遍历每个帖子并确定哪个帖子属于哪个用户,并向他们显示属于当前登录用户的帖子。

      更改发布表名称后,我得到了这个异常

      org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#2
      

      这告诉我 id 为 2 的用户对象在新用户表中不可用。

      然后我又注册了一个 id 为 2 的用户,后来我得到了这个

      org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#3
      

      这次它找不到 id 为 3 的用户

      终于注册了第三个用户,没有异常。

      如您所见,post 表中存在外键,但由于我更改了 user 表,因此无法匹配它们,这就是我遇到此问题的原因。

      为了避免这种情况,我为这两个对象创建了新的表名并重新开始

      希望对你有帮助

      【讨论】:

        【解决方案7】:

        我没有看到与代码中的异常有关的任何实际问题,您可能想尝试一下:

        • 提交后检查事务是否刷新或手动调用flush()
        • 通过调试器检查ID是否传递给load()以及正确的ID是否传递给它
        • 启用 Hibernate 以打印生成的 SQL 和/或启用日志记录

        【讨论】:

        • 我尝试了所有 3 个建议,但没有一个有帮助,尽管 flush() 降低了它的发生频率(即它有时会起作用!非常奇怪)。还有其他想法吗?
        • @nastypasty 至少可以这么说,这很奇怪。我能想到的最好的方法是设置 Hibernate 日志记录配置并检查 TRACE 级别日志,这应该向您显示问题并且对于那么小的 INSERT,它们应该是可读的。你需要一个日志后端来支持它,我建议logback,但是 slf4j 支持很多其他的。如果您告诉我您选择哪一个,我想如果您遇到任何问题,我可以帮助您进行设置...
        【解决方案8】:

        我在 hibernate 3.6.10 中遇到了类似的问题,而我只是在搜索和选择(如果存在)。

        注释:

        @Entity
        public class Familiares {
        @OneToMany(mappedBy = "familiares")
        private List<FamiliaresBaja> bajas;
        
        @Entity
        @Table(name = "familiares_baja")
        public class FamiliaresBaja implements Serializable {
        
            private static final long serialVersionUID = 1L;
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private Integer id;
            @JoinColumn(name = "familiares_id")
            @ManyToOne(optional = false)
            private Familiares familiares;
        

        然后我检索一个列表,如果至少有一个,则在 FamiliaresBaja 中查找这些列表。

        createQuery("from FamiliaresBaja where familiares.id="+ id).uniqueResult() // should return a single result or null not throw a Exception
        

        这一定是 Hibernate 错误

        【讨论】:

        • 那么这是一个解决方案还是看起来如何?
        • 不,我只是通过一个非常简单的例子来强化一个错误,一个大错误的想法
        【解决方案9】:

        请检查你的mysql服务器的lower_case_table_names的值。如果值为0,检查hibernate生成的SQL,确保表名大小写与mysql中实际表名一致。

        【讨论】:

          【解决方案10】:

          检查触发器,如果​​您有一个前插入触发器,并且序列中有 NEXTVAL,则会导致该错误。

          【讨论】:

            【解决方案11】:

            您可能在使用不同 ID 查找的实体中存在一对一关系,请尝试在映射表中加载具有 ID 的实体,而不是在标识列中。

            【讨论】:

              【解决方案12】:

              解决这个问题的正确方法是使用session.get() 方法。如果未找到实体,Get 方法将返回 null

              【讨论】:

              • 您能详细说明一下吗?
              【解决方案13】:
              Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.emmanuel.Entity.Classe#17]
              at org.hibernate.boot.internal.StandardEntityNotFoundDelegate.handleEntityNotFound(StandardEntityNotFoundDelegate.java:28)
              at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:216)
              at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:327)
              at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108)
              at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74)
              at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118)
              at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1215)
              at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1080)
              at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:697)
              at org.hibernate.type.EntityType.resolve(EntityType.java:464)
              at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:240)
              at org.hibernate.engine.internal.TwoPhaseLoad$EntityResolver.lambda$static$0(TwoPhaseLoad.java:576)
              at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntityEntryLoadedState(TwoPhaseLoad.java:221)
              at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:155)
              at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:126)
              at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1201)
              at org.hibernate.loader.Loader.processResultSet(Loader.java:1009)
              at org.hibernate.loader.Loader.doQuery(Loader.java:967)
              at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357)
              at org.hibernate.loader.Loader.doList(Loader.java:2868)
              at org.hibernate.loader.Loader.doList(Loader.java:2850)
              at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682)
              at org.hibernate.loader.Loader.list(Loader.java:2677)
              at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
              at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1906)
              at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:370)
              

              我遇到了同样的问题,我之前删除了一个在另一个表中引用的对象,当我加载对象时,我在表中有一个外键,它没有引用任何内容,因此出现此异常。

              [com.emmanuel.Entity.Classe#17] 指定在我要加载其对象的表中以 id 17 引用的对象不存在.

              【讨论】:

                猜你喜欢
                • 2013-03-29
                • 2015-06-02
                • 2014-01-14
                • 1970-01-01
                • 2011-02-20
                • 1970-01-01
                • 2013-08-28
                相关资源
                最近更新 更多