告诉Hibernate忽略脏检查中的属性

时间:2015-11-26 03:32:36

标签: java hibernate

我一直试图弄清楚如何解决这个问题。很糟糕的是,hibernate没有提供准备使用注释来从脏检查中排除属性。 这是问题,我有一个课程如下

Class A {
@Column 
Property 1
@Column 
Property 2..etc

@Column
Date lastUpdateDate
@Column
String lastUpdateBy
}

我想从脏检查中排除lastUpdateDate和lastUpdateBy! 这就是我正在做的事情

  1. 使用Dynamic-Update = true

  2. 使用拦截器和覆盖findDirty方法来告诉hibernate对象是否脏(这里,previousState总是为null因为对象是瞬态的,所以无法比较旧值)

  3. merge会修复这个问题,但它会导致性能问题(几百万条记录)所以我必须使用saveOrUpdate,它不会将previousState传递给Interceptor

  4. 还有其他方法可以解决这个问题吗?

4 个答案:

答案 0 :(得分:1)

尝试将updateable = false添加到@Column。它导致该字段不包含在更新语句中,因此我认为它会将其从脏检查中排除。

点击此链接:

MDN

答案 1 :(得分:1)

您可以使用@OptimisticLock(excluded = true)将其从脏检查中排除。

DOCS

答案 2 :(得分:1)

可以从脏检查中忽略特定的实体字段。您必须像这样覆盖DefaultFlushEntityEventListener

@Component
public class CustomFlushEntityEventListener extends DefaultFlushEntityEventListener {

    private static final List<String> IGNORE_DIRTY_CHECK_PROPERTIES = List.of(
        "lastModifiedBy",
        "lastModifiedDate"
    );

    @Override
    protected void dirtyCheck(final FlushEntityEvent event) throws HibernateException {
        super.dirtyCheck(event);
        removeIgnoredDirtyCheckProperties(event);
    }

    private void removeIgnoredDirtyCheckProperties(final FlushEntityEvent event) {
        var propertyNames = event.getEntityEntry().getPersister().getPropertyNames();
        var dirtyProperties = event.getDirtyProperties();
        if(dirtyProperties == null) return;

        var newDirtyProperties = new java.util.ArrayList<Integer>();

        for (int dirtyProperty : dirtyProperties) {
            if (!IGNORE_DIRTY_CHECK_PROPERTIES.contains(propertyNames[dirtyProperty])) {
                newDirtyProperties.add(dirtyProperty);
            }
        }

        var newDirtyPropertiesArray = newDirtyProperties.stream().mapToInt(i -> i).toArray();
        event.setDirtyProperties(newDirtyPropertiesArray.length > 0 ? newDirtyPropertiesArray : null);
    }

}

,然后替换侦听器:

@Component
@RequiredArgsConstructor
public class HibernateListenerConfigurer {

    private final EntityManagerFactory entityManagerFactory;
    private final CustomFlushEntityEventListener customFlushEntityEventListener;

    @PostConstruct
    protected void init() {
        SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.FLUSH_ENTITY).clear();
        registry.getEventListenerGroup(EventType.FLUSH_ENTITY).appendListener(customFlushEntityEventListener);
    }

}

您还可以将IGNORE_DIRTY_CHECK_PROPERTIES列表替换为实体属性上的自定义注释,例如@IgnoreDirtyCheck,并通过反射从event.getEntity()中读取。

答案 3 :(得分:0)

你应该使用hibernate / JPA实体监听器来更新你的属性(lastUpdateDate)

https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html

它比使用自己的脏检查更容易使用标准解决方案。