Следующий код пытается вставить Item
возразите против дб, с помощью Spring+Hibernate. Объект имеет Целочисленное идентификационное поле как первичный ключ, а также a name
столбец, который подвергается ограничению на уникальность данных (упрощенный пример).
Я знаю, что идентификатор объекта является пустым (объект является переходным), однако, вставка может все еще перестать работать из-за ограничения на уникальность данных на поле имени.
try {
getHibernateTemplate().save(myItem);
getHibernateTemplate().flush(); // exception thrown here if the name is not unique
}
catch (DataIntegrityViolationException e) {
Item itemFromDb = (Item) getHibernateTemplate()
.find("from Item item where item.name = ?",
myItem.getName()).get(0);
//
// copy some properties from myItem to itemFromDb
//
getHibernateTemplate.update (itemFromDb)
}
Мне нужен этот код для выполнения в цикле за многими объектами, всеми в одной транзакции, вот почему я пытаюсь выпустить обновление, если вставка перестала работать.
Однако после сбоев вставки, быть в спящем режиме сессия находится в странном состоянии, и когда я делаю избранное заявление для получения объекта из дб, исходное исключение выдается.
Я пытался использовать session.evict()
после сбоев вставки, но напрасно. Какая-либо идея?
Это - то, что я вижу в консоли после избранных сбоев. Будьте в спящем режиме сбои на избранном операторе, но все еще печатает информацию о предыдущем операторе вставки.
WARN [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:77) - SQL Error: 2627, SQLState: 23000
ERROR [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:78) - Violation of UNIQUE KEY constraint 'unq_Item_name'. Cannot insert duplicate key in object 'items'.
ERROR [http-8080-1] event.def.AbstractFlushingEventListener (AbstractFlushingEventListener.java:301) - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert: [com.sample.Item]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
P.S. не говорите мне о saveOrUpdate методе hibernate, я знаю то, что он делает.
Hibernate не дает никаких гарантий относительно сеанса после того, как возникло исключение базы данных. Вы должны откатиться. Если я понимаю предложение Божо, он говорит, что вы должны сначала прочитать столбец имени, чтобы убедиться, что вставка не потерпит неудачу. Для меня это имеет смысл.
getHibernateTemplate().merge(myItem);
merge - копирование состояния данного объекта на постоянный объект с тем же идентификатором. Если в настоящее время нет постоянного экземпляра, связанного с сессией, он будет загружен. Вернуть постоянный экземпляр. Если данный экземпляр не сохранен, сохраните его копию и верните ее как новый персистентный экземпляр. Данный экземпляр не становится ассоциированным с сессией. Эта операция каскадируется на ассоциированные экземпляры, если ассоциация отображена с cascade="merge".