我在我的应用程序中尝试了域类的 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/