Сейчас многие любят реализовывать Data Access Object (DAO) на базе Hibernate.
Хотелось уделить особое внимание работе с объектами в различных состояниях.
Пример из документации :
DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
cat.setName("PK");
sess.flush(); // changes to cat are automatically detected and persisted
Некоторые думают, что нужно делать так:
DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
cat.setName("PK");
sess.update(cat); // НЕ НАДО, ОНО САМО СОХРАНИТСЯ !!!! REMOVE THIS LINE
sess.flush(); // changes to cat are automatically detected and persisted
Это является следствием непонимания работы Hibernate и различий между PERSISTENT, TRANSIENT или DETACHED состоянием объектов.
В популярной статье на хабре Основы Hibernate приводится такой способ реализации DAO:
public class BusDAOImpl implements BusDAO {
...
public void updateBus(Long bus_id, Bus bus) throws SQLException {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.update(bus);
session.getTransaction().commit();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Ошибка при вставке", JOptionPane.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
}
...
}
Все хорошо, но какой мы должны передавать объект bus – PERSISTENT, TRANSIENT или DETACHED?
Возможно именно эти неудобства приводят к использованию антипаттерна session-per-operation, когда мы открываем новую сессию на каждый чих. Подробнее можно прочитать в документации:
“Do not use the session-per-operation antipattern: do not open and close a Session for every simple database call in a single thread. “