StaleStateException при удалении через спящий режим - PullRequest
1 голос
/ 20 июля 2011

Я опробовал в своем приложении отображение гибернации для классов доменов - Book, Author и Publisher. Я хотел удалить Publisher или Author, у которых нет Books.So, я кодировал логику добавления / удаления книги, как показано ниже.

При удалении книги проверяется размер набора книг в Author и Publisher. Если они содержат только один экземпляр книги (который будет удален), то Author и Publisher удаляются.удалены из их наборов книг.

В моей программе я поместил кодовый блок для проверки размера Set и удаления Author перед размером Publisher, как показано во фрагменте.

Когда я удаляю все книгиавтора удаляется успешно. Но издатель удаления вызывает исключение StaleStateException.Фактическое отслеживание ошибок дается в конце. Теперь, в качестве последнего усилия, я поменял блоки кода, которые удаляют Publisher и Author, и поместил deletePublisher (publisher) перед блоком, содержащим deleteAuthor (author). Теперь Publisher получаетудалено, но удаление Author вызывает StaleStateException.

Я не мог понять, была ли какая-то проблема в моей логике. Попытка регистрации и обнаружение, что в моем методе GenericDao.delete (Object obj), исключение происходит непосредственно передПроизошла транзакция и произошел откат. Я также перечислил соответствующие части кода реализации Dao.

Если кто-то может помочь ... пожалуйста, скажите мне, как я могу решить эту ошибку.

спасибо

mark

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>

Создание книги добавляет экземпляр книги к наборам в Author и Publisher.

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();
        }

    }
}

And вот след от кота

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 Ответ

3 голосов
/ 21 июля 2011

Это потому, что вы начинаете и заканчиваете транзакции в ваших методах DAO.Это не хороший выбор.Вы должны использовать декларативные транзакции как , предоставленные Spring или какой-либо другой платформой.Происходит следующее: когда вы удаляете автора, книга также удаляется.(Хотя я не верю, что это явно упоминается в документации по Hibernate, в исходном коде 1004 * вы можете видеть, что cascade="delete-orphan" подразумевает cascade="delete".) После этого вы фиксируете транзакцию, что означает, что оба Автори книга была удалена.Ваш экземпляр Publisher, тем не менее, все еще содержит ссылку на книгу, которая была удалена, т.е. он имеет устаревшее состояние.Поэтому, когда вы пытаетесь удалить Издателя и, каскадом, Книгу снова, вы получаете исключение StaleStateException.Управление вашими транзакциями на более высоком уровне вашего приложения предотвратит это, так как все автор, издатель и книга будут удалены в одной транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...