Java Hibernate拦截器-为什么在onSave之后调用onFlushDirty? 计划

Java Hibernate拦截器-为什么在onSave之后调用onFlushDirty? 计划,java,hibernate,state,updates,interceptor,Java,Hibernate,State,Updates,Interceptor,我正在使用Hibernate为一个小项目实现createDate和lastUpdate时间戳。我使用一个EmptyInterceptor,并根据我找到的建议解决方案重载提供的方法。 除非有一点细节,否则这个解决方案很好用。我想添加一列,指示对象是否已经更新。我知道我可以通过简单地比较两个创建和更新的时间戳是否有差异来实现这一点,但是我需要有这个字段来指示有一个更新 我使用onSave方法,在存储新对象时调用该方法,将wasUpdated值设置为“N”,表示没有更新。在onFlushDirty()

我正在使用Hibernate为一个小项目实现createDate和lastUpdate时间戳。我使用一个EmptyInterceptor,并根据我找到的建议解决方案重载提供的方法。 除非有一点细节,否则这个解决方案很好用。我想添加一列,指示对象是否已经更新。我知道我可以通过简单地比较两个创建和更新的时间戳是否有差异来实现这一点,但是我需要有这个字段来指示有一个更新

我使用onSave方法,在存储新对象时调用该方法,将wasUpdated值设置为“N”,表示没有更新。在onFlushDirty()方法中,我将该值设置为“Y”

问题 我想解释一下,当我创建并持久化一个新对象时,createDate和lastUpdate字段具有相同的日期,但是wasUpdate字段被设置为“N”,因为没有更新。我在代码中只使用session.save(),没有session.update(),也没有session.saveOrUpdate()。Hibernate的日志表明实际上有一个更新,它将wasUpdated值设置为“Y”

此更新的来源是什么?它在哪里触发?

对象初始化和持久性 我在hibernate.cfg.xml中禁用了自动提交

<property name="hibernate.connection.autocommit">false</property>
拦截器 第二种方法是设置lastUpdateDate并将wasUpdated字段设置为“Y”

@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
                    Object[] previousState, String[] propertyNames, Type[] types) {

    if (entity instanceof TimeStamped) {

        int indexOfLastUpdate = ArrayUtils.indexOf(propertyNames, "lastUpdatedDate");
        int indexOfWasUpdated = ArrayUtils.indexOf(propertyNames, "wasUpdated");

        currentState[indexOfLastUpdate] = new Date();
        currentState[indexOfWasUpdated] ='Y';


        return true;
    }
    return false;
}
冬眠 我在会话中使用此配置

public class HibernateUtil {
    private static SessionFactory sessionFactory;
    private static ServiceRegistry serviceRegistry;

    static {
    try {

        Configuration configuration = new Configuration().setInterceptor(new TimeStampInterceptor());
        configuration.configure();

        serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);


    } catch (HibernateException he) {
        System.err.println("Error creating Session: " + he);
        throw new ExceptionInInitializerError(he);
    }
    }

    public static SessionFactory getSessionFactory() {
    return sessionFactory;
    }
}
版本 我使用Maven和Java1.7.0\u40

    <!--. Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.4.Final</version>
    </dependency>

org.hibernate
冬眠核心
4.3.4.最终版本

onFlushDirty()方法的JavaDoc具有以下语句:

在冲洗过程中检测到对象变脏时调用

因此,对象是由于
update()
调用而变脏,还是由于
save()
调用而变脏,这两者之间没有区别。因此,会话刷新时,将对每个持久对象调用
onFlushDirty()
方法。会话刷新可以由
Session.flush()
显式启动,也可以在Hibernate需要时隐式启动(在您的情况下,在事务提交之前)。

在您的情况下,
wasdupdated
属性将始终使用“Y”值保存:首先将调用
onSave()
方法,当会话刷新时,将在同一实体上调用
onFlushDirty()
方法。

要解决
onFlushDirty()
方法中的问题,您应该检查实体是否已更新。若我的内存正常,那个么当实体插入到表中(保存新的)时,前一个状态为null。建议像这样实现
onFlushDirty()

@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
                    Object[] previousState, String[] propertyNames, Type[] types) {

    if (entity instanceof TimeStamped && previousState!=null) {

        int indexOfLastUpdate = ArrayUtils.indexOf(propertyNames, "lastUpdatedDate");
        int indexOfWasUpdated = ArrayUtils.indexOf(propertyNames, "wasUpdated");

        currentState[indexOfLastUpdate] = new Date();
        currentState[indexOfWasUpdated] ='Y';


        return true;
    }
    return false;
}
解决方案: 多亏@vp8106的提示,我可以解决这个问题。当我在记录初始化期间将
lastUpdate
值设置为与
creationDate
值相同的日期时,我只是比较这两个日期。如果它们相同,那么这是第一次更新,我需要将更新指示符
wasdupdated
设置为
'Y'

代码段:
我实现了一个类似的东西,它工作起来没有任何问题。有以下区别:

  • 我使用no
    wasdupdated
    来比较
    createdDate
    lastdupdateDate
    就足够了
  • 我使用
    lastUpdateDate
    进行hibernate版本控制(需要毫秒精度才能工作),所以我不必自己设置


如果我是OP,我会问自己是否真的需要
wasdupdated
作为一个字段。这显然是多余的,因为它可以在任何时候计算,就像OP在他的回答中所做的那样。
timestamp
上的只读属性应该可以。

不幸的是,您的回答没有解决问题,但它给了我正确的提示。在以前的状态中检查null不起作用,因为我需要在与创建日期相同的DAT上设置
lastUpdate
值。尽管如此,还是非常感谢你,它帮助我更好地理解了这个问题。
    <!--. Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.4.Final</version>
    </dependency>
@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
                    Object[] previousState, String[] propertyNames, Type[] types) {

    if (entity instanceof TimeStamped && previousState!=null) {

        int indexOfLastUpdate = ArrayUtils.indexOf(propertyNames, "lastUpdatedDate");
        int indexOfWasUpdated = ArrayUtils.indexOf(propertyNames, "wasUpdated");

        currentState[indexOfLastUpdate] = new Date();
        currentState[indexOfWasUpdated] ='Y';


        return true;
    }
    return false;
}
   @Override
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
                            Object[] previousState, String[] propertyNames, Type[] types) {




    /**
     * Update the lastUpdateDate value and set the wasUpdated flag to 'Y'
     */
    if (entity instanceof TimeStamped) {


        int indexOfLastUpdate = ArrayUtils.indexOf(propertyNames, "lastUpdatedDate");
        int indexOfCreatedDate = ArrayUtils.indexOf(propertyNames, "createdDate");
        int indexOfWasUpdated = ArrayUtils.indexOf(propertyNames, "wasUpdated");

        Date createdDate = (Date) previousState[indexOfCreatedDate];
        Date lastUpdateDate = (Date) currentState[indexOfLastUpdate];


        /**
         * If createdDate equals lastUpdateDate, this is the first update.
         * Set the updated column to Y
         */
        if (createdDate.equals(lastUpdateDate)) {
            logger.warning("This is the first update of the record.");
            currentState[indexOfWasUpdated] = 'Y';
        }
        // set the new date of the update event
        currentState[indexOfLastUpdate] = new Date();


        return true;
    }
    return false;
}
public boolean onSave(Object entity, Serializable id, Object[] state,
              String[] propertyNames, Type[] types) {

    if (entity instanceof TimeStamped) {
        Date insertDate = new Date();
        int indexOfCreateDateColumn = ArrayUtils.indexOf(propertyNames, "createdDate");
        state[indexOfCreateDateColumn] = insertDate;
        return true;
    }
    return false;
}