Из-за требований к архитектуре мы не можем использовать наши объекты Hibernate как DTO, поэтому мы используем Dozer для преобразования этих объектов в POJO.Hibernate - установка нуля в коллекции объектов автоматически сохраняется при фиксации транзакции
Наш типичный сервис выглядит следующим образом:
@Transactional(readOnly=true)
@Override
public Task loadTask(int taskId){
TaskEntity taskE = taskDAO.load(taskId);
if (taskE != null){
taskE.setAttachments(null)
Task task = objectMapper.convert(taskE, Task.class);
return task;
}else{
return null;
}
}
Как вы можете видеть, до трансформации TaskEntity к задаче мы устанавливаем вложения в нуль. Это связано с тем, что вложения представляют собой ленивую коллекцию, и мы не хотим излишне запускать загрузку этих объектов.
Перед обновлением до весны 4.1.1 это сработало без проблем. Однако недавно мы обновили Spring с 3.2.7, оставив Hibernate на 3.6.10. Затем, при выполнении этого же кода, который мы заметили, что Hibernate выполнял это заявление после выполнения loadTask:
update TaskAttachment set taskId = NULL where id= ?
То есть, из-за установки нуля в taskEntity.attachments, Hibernate удаляет внешний ключ в TaskAttachment.
Свойства конфигурации: spring.transactionManager_class = org.springframework.transaction.jta.WebSphereUowTransactionManager hibernate.transaction.manager_lookup_class = org.hibernate.transaction.WebSphereExtendedJTATransactionLookup hibernate.current_session_context_class = JTA hibernate.transaction.factory_class = org.hibernate.transaction.JTATransactionFactory jta.UserTransaction = Java: комп/UserTransaction
Factory Session Config
<bean id="mainSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="jtaTransactionManager" ref="jtaTransactionManager" />
<property name="dataSource" ref="mainDataSource" />
<property name="packagesToScan" ref="packages-mainSessionFactory" />
<property name="hibernateProperties" ref="properties-mainSessionFactory" />
</bean>
Единственная связанная с ORM вещь, которую мы изменили, заключалась в том, что мы прекратили использовать HibernateTemplate в пользу SessionFactory.getCurrentSession().
Наши бывшие BaseDAO:
public abstract class BaseDAO<EntityType extends BaseEntity<IdType>, IdType extends Serializable> extends HibernateDaoSupport
public BaseDAO(HibernateTemplate hibernateTemplate, Class<EntityType> clazz){
super();
super.setHibernateTemplate(hibernateTemplate);
this.clazz= clazz;
}
public EntityType load(IdType id){
return getHibernateTemplate().get(clazz, id);
}
Наш текущий BaseDAO:
@SuppressWarnings("unchecked")
public abstract class BaseDAO<EntityType extends BaseEntity<IdType>, IdType extends Serializable> implements IBaseDAO<EntityType, IdType>{
private Class<EntityType> clazz;
private SessionFactory sessionFactory;
public BaseDAO(SessionFactory sessionFactory, Class<EntityType> clazz){
super();
this.clazz= clazz;
this.sessionFactory=sessionFactory;
}
public EntityType load(IdType id){
return (EntityType)getSession().get(clazz, id);
}
protected Session getSession(){
return sessionFactory.getCurrentSession();
}
UPDATE: Это не весна версия. Связанный с этим вопрос Я проверил, что с использованием HibernateTemplate.get() он не сохраняет нуль, а с SessionFactory.getCurrentSession(). Get() он делает, почему?
В чем проблема, с которой вы столкнулись? – kondu
Извините, что я случайно не опубликовал до окончания, дайте мне 10 минут – codependent
Это то, что я ожидал увидеть до вашего обновления. Вы меняете управляемый объект внутри транзакции. Значение hibernate будет отслеживать все изменения, и когда commit/end будет сохраняться в базе данных. По крайней мере, это будет так, если этот метод вызывается из другого метода @ @ Transactional. (Не могли бы вы также добавить из какой версии версию, которую вы обновляете)? –