hibernate - 通过 hibernate 删除时出现 StaleStateException

标签 hibernate exception

我在我的应用程序中尝试了域类的 hibernate 映射 - 即书籍、作者和出版商。我想删除没有书籍的出版商或作者。因此,我编写了添加/删除书籍的逻辑,如下所示.

删除书籍会检查作者和出版商中书籍集的大小。如果它们仅包含单个书籍实例(将要删除),则作者和出版商将被删除。否则该书籍将从其集中删除本书。

在我的程序中,我将用于检查 Set 大小并删除 Author 的代码块放在 Publisher 之前,如代码片段所示。

当我删除某个作者的所有书籍时,该作者已成功删除。但是删除出版商会导致 StaleStateException。 实际的错误回溯在最后给出。 现在,作为最后的努力,我交换了删除 Publisher 和 Author 的代码块,并将 deletePublisher(publisher) 放在包含 deleteAuthor(author) 的代码块之前。现在,Publisher 被删除,但删除 Author 会导致 StaleStateException。

我无法弄清楚我的逻辑是否存在问题。尝试记录日志,发现在我的 GenericDao.delete(Object obj) 方法中,异常发生在 transaction.commit() 和回滚发生之前。我还列出了Dao相关部分的实现代码。

如果有人可以帮忙..请告诉我如何解决这个错误。

谢谢

标记

public class Book {
    private Long book_id;   
    private String name;
    private Author author;
    private Publisher publisher;
        ...
}

public class Author {
    private Long author_id;
    private String name;
    private Set<Book> books;

    public Author() {
        super();
        books = new HashSet<Book>();
    }
        ...
}
public class Publisher {
    private Long publisher_id;
    private String name;
    private Set<Book> books;
    public Publisher() {
        super();
        books = new HashSet<Book>();

    }
       ...
}

Book.hbm.xml有

<many-to-one name="publisher" class="Publisher" column="PUBLISHER_ID" lazy="false" cascade="save-update"/>
<many-to-one name="author" class="Author" column="AUTHOR_ID" lazy="false" cascade="save-update"/>

作者.hbm.xml

...
<set name="books" inverse="true" table="BOOK" lazy="false" order-by="BOOK_NAME asc" cascade="delete-orphan">
            <key column="AUTHOR_ID" />
            <one-to-many class="Book" />
</set>

Publisher.hbm.xml

<set name="books" inverse="true" table="BOOK" lazy="false" order-by="BOOK_NAME asc" cascade="delete-orphan">
            <key column="PUBLISHER_ID" />
            <one-to-many class="Book" />
</set>

创建书籍会将书籍实例添加到作者和出版商的集中。

doPost(HttpServletRequest request, HttpServletResponse response){
   ...
   Book book = new Book();
   ...
   Publisher publisher = createPublisherFromUserInput();
   Author author = createAuthorFromUserInput();
   ...
   publisher.getBooks().add(book);
   author.getBooks().add(book);
   bookdao.saveOrUpdateBook(book);
}

删除图书

 doPost(HttpServletRequest request, HttpServletResponse response){
      ...
      Book bk = bookdao.findBookById(bookId);
       Publisher pub = bk.getPublisher();
       Author author = bk.getAuthor();
       if (author.getBooks().size()==1){
        authordao.deleteAuthor(author);

        }else{
          author.getBooks().remove(bk);

        }
       if(pub.getBooks().size()==1){
            publisherdao.deletePublisher(pub);

        }else{
              pub.getBooks().remove(bk);

        }
        bookdao.deleteBook(bk);

    }

Dao 实现

public class PublisherDao extends GenericDao{
   @Override
    public void deletePublisher(Publisher publisher) {
        String name = publisher.getName();
        logger.info("before delete pub="+name);
        delete(publisher);
        logger.info("deleted pub="+name);

    }
        ...
}

public abstract class GenericDaoImpl{       
   @Override
    public void delete(Object obj) {
        SessionFactory factory = HibernateUtil.getSessionFactory();
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.delete(obj);
            logger.info("after session.delete(obj)");
            logger.info("delete():before tx.commit");//till here no exception
            tx.commit();
        } catch (HibernateException e) {
        if (tx != null) {
            tx.rollback();
            logger.info("delete():txn rolled back");//this happens when all Books are deleted
        }
            throw e;
        } finally {
            session.close();
        }

    }
}

这是来自 tomcat 的跟踪

SEVERE: Servlet.service() for servlet deletebookservlet threw exception
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at 

...
org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(ExpectationImpl.managedFlush(SessionImpl.java:375)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
    at bookstore.dao.GenericDao.delete(Unknown Source)
    at bookstore.dao.PublisherDao.deletePublisher(Unknown Source)
    at bookstore.servlets.MyBookDeleteServlet.doPost(Unknown Source)

最佳答案

这是因为您在 DAO 方法中开始和结束事务。这不是一个好的选择。您应该使用声明性事务作为 provided by Spring或其他一些框架。发生的情况是,当您删除作者时,该书也会被删除。 (虽然我不相信 Hibernate 文档中明确提到了这一点,但您可以在 source code 中看到 cascade="delete-orphan" 暗示 cascade="delete".) 之后,您提交事务,这意味着 Author 和 Book 都已被删除。不过,您的 Publisher 实例仍然具有对已删除的图书的引用,即它有陈旧的状态。因此,当您尝试再次删除 Publisher 并通过级联删除 Book 时,您会收到 StaleStateException。在应用的更高级别管理事务可以防止这种情况发生,因为作者、出版商和图书都将在同一事务中被删除。

关于hibernate - 通过 hibernate 删除时出现 StaleStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6763268/

相关文章:

java - Hibernate 库和 Hibernate JPA 库的区别

Hibernate 命名查询数据库或缓存?

java - 我应该如何解决这种错误

python - 在 Python3 中构建模块异常的最佳实践

java - 在 Hibernate 实体中合并表的字段

java - Hibernate 单表数据库的可行性

java - Hibernate session.flush() 即使设置了自动提交

python - 脚本完成后 python 垃圾收集时出现奇怪的线程错误

java - java中如何处理抛出检查异常的方法

c# - Azure Functions V3 在启动文件中记录异常