Hibernate - 在事务提交

时间:2015-06-19 09:53:10

标签: java spring hibernate dozer

由于架构要求,我们无法将Hibernate实体用作DTO,因此我们使用Dozer将这些实体转换为POJO。

我们的典型服务如下:

@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转换为Task之前,我们将附件设置为null。这是因为附件是一个懒惰的集合,我们不希望不必要地触发这些实体的加载。

在更新到Spring 4.1.1之前,这没有任何问题。但是,最近我们将Spring升级到3.2.7,让Hibernate升级到3.6.10。然后,当执行相同的代码时,我们注意到Hibernate在loadTask执行后执行了这个语句:

update TaskAttachment set taskId = NULL where id= ?

也就是说,因为在taskEntity.attachments中设置了null,所以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的:COMP / UserTransaction的

会话工厂配置

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

更新:这不是与Spring相关的问题。我已经检查过使用 HibernateTemplate.get()它不会保留null,并且使用 SessionFactory.getCurrentSession()。get()它确实如此?

2 个答案:

答案 0 :(得分:1)

@Transactional(readOnly=true)告诉Spring,操作不会修改数据库,在这种情况下,它将连接设置为只读,而Hibernate不会更新实体。如果您删除readOnly=true,您会看到即使使用HibernateTemplate.get(),也会保留更改。

如果您使用SessionFactory.getCurrentSession(),那么您将绕过Spring的初始化部分,将会话设置为只读,因此更改会保持不变。

依赖readOnly=true禁止更新不是一个好习惯,因为并非所有数据库和ORM都支持它。最好的做法是使用Session.evict()来分离实体。无论如何保持readOnly=true,因为如果DB / ORM支持它,那么可以针对只读操作优化数据库访问。

答案 1 :(得分:-1)

而不是将您的集合设置为null ...更改实体中的级联选项,以便在保存父级时不会保存子级。