通过hibernate删除时出现StaleStateException

时间:2011-07-20 14:07:31

标签: hibernate exception

我尝试了我的应用程序中的域类的hibernate映射 - Book,Author和Publisher。我想删除没有Books的发布者或作者。所以,我编写了添加/删除Book的逻辑,如下所示

删除图书会检查作者和出版商中的图书集的大小。如果它们只包含单个图书实例(将要删除),则删除作者和出版商。删除图书中的图书书。

在我的程序中,我将代码块用于检查Set的大小,并在发布者之前删除作者,如代码段所示。

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

我无法弄清楚我的逻辑中是否存在某些问题.Tried日志记录并发现在我的GenericDao.delete(Object obj)方法中,异常发生在transaction.commit()和rollback发生之前.I还列出了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"/>

Author.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)

1 个答案:

答案 0 :(得分:3)

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