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