JPA: persist() молча, без исключений не вносит изменения в БД Postgres, но прибавляет счетчик ID
Не срабатывает запись persist() для тех же объектов, которые нормально читаются, удаляются и обновляются посредством JPA. В базе Postgres есть таблица students:
CREATE TABLE students
(
person_id SERIAL PRIMARY KEY,
group_id INTEGER REFERENCES groupz (group_id),
student_year INTEGER,
person_name CHARACTER VARYING(30)
);
Класс Student наследует ID-поле у родителя Person:
@MappedSuperclass
public abstract class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected int person_id;
public int getId() {
return person_id;
}
...
У Person также есть дочерний класс Professor, он нормально пишется с persist(). Метод из DAO-класса:
public boolean create(Student student) throws DAOException {
boolean result = false;
try {
EntityManager em = emf.getFactory().createEntityManager();
em.getTransaction().begin();
em.persist(student);
em.flush();
em.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new DAOException("Could not create Student", e);
}
return result;
}
Странно, что нет exceptions в логах, консоли и т.п. SQL-запрос отражается в консоли - он валиден, точно такой же запрос в pgAdmin дает нужный результат. При этом, когда я делаю это через pgAdmin, новая запись приходит с намного большим ID - сообразно количеству неудачных попыток сделать запись при помощи JPA/Hibernate.
Ответы (1 шт):
Описанное поведение (ID успешно зарезервированы, но ни одной записи с ними не видно) явно указывает на незавершенные (открытые) транзакции.
Postgres получил данные, выделил под них ресурсы, но держит в заблокированном состоянии до тех пор, пока транзакции не будут закрыты (commit). Теоретически - увидеть данные можно, используя "грязное чтение" (read uncommited), но скорее всего по истечению времени транзакции будут автоматически закрыты и данные пропадут.
Верное решение здесь - в явном виде завершить транзакцию, которая в рамках единственного действия, по большому счету, и не нужна. В итоге, должно получиться что-то вроде:
public boolean create(Student student) throws DAOException {
boolean result = false;
EntityManager em = emf.getFactory().createEntityManager();
EntityTransaction trn = em.getTransaction();
try {
trn.begin();
em.persist(student);
em.flush();
em.close();
trn.commit();
} catch (Exception e) {
trn.rollback();
logger.error(e.getMessage(), e);
throw new DAOException("Could not create Student", e);
}
return result;
}