34

我使用的是 Hibernate 4.3.6,并使用了最新的Maven 字节码增强功能来检测所有实体的自我肮脏意识。

我添加了 Maven 插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.hibernate.orm.tooling</groupId>
            <artifactId>hibernate-enhance-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>process-test-resources</phase>
                    <goals>
                        <goal>enhance</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

我看到我的实体正在得到增强:

@Entity
public class EnhancedOrderLine
implements ManagedEntity, PersistentAttributeInterceptable, SelfDirtinessTracker
{
    @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private Long number;
  private String orderedBy;
  private Date orderedOn;

  @Transient
  private transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor;

  @Transient
  private transient Set $$_hibernate_tracker;

  @Transient
  private transient CollectionTracker $$_hibernate_collectionTracker;

  @Transient
  private transient EntityEntry $$_hibernate_entityEntryHolder;

  @Transient
  private transient ManagedEntity $$_hibernate_previousManagedEntity;

  @Transient
  private transient ManagedEntity $$_hibernate_nextManagedEntity;

  ...

在调试时,我正在检查org.hibernate.event.internal.DefaultFlushEntityEventListener#dirtyCheck方法:

        if ( entity instanceof SelfDirtinessTracker ) {
            if ( ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes() ) {
                dirtyProperties = persister.resolveAttributeIndexes( ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() );
            }
        }

并且$$_hibernate_hasDirtyAttributes()总是返回false

这是因为$$_hibernate_attributeInterceptor始终为空,所以在设置任何属性时:

private void $$_hibernate_write_number(Long paramLong)
{
 if (($$_hibernate_getInterceptor() == null) || ((this.number == null) || (this.number.equals(paramLong))))
  break label39;
 $$_hibernate_trackChange("number");
 label39: Long localLong = paramLong;
 if ($$_hibernate_getInterceptor() != null)
  localLong = (Long)$$_hibernate_getInterceptor().writeObject(this, "number", this.number, paramLong);
 this.number = localLong;
}

因为$$_hibernate_getInterceptor()为 null,trackChange 将被绕过,因此字节码增强不会解决脏属性,并且将使用默认的深度比较算法。

我错过了什么?如何$$_hibernate_attributeInterceptor正确设置,以便字节码检测方法跟踪脏属性?

4

2 回答 2

4

Hibernate 5 修复了这个问题,现在对 setter 的脏检查看起来像这样:

public void $$_hibernate_write_title(String paramString)
{
    if (!EqualsHelper.areEqual(this.title, paramString)) {
      $$_hibernate_trackChange("title");
    }
    this.title = paramString;
}

public void $$_hibernate_trackChange(String paramString)
{
    if (this.$$_hibernate_tracker == null) {
      this.$$_hibernate_tracker = new SimpleFieldTracker();
    }
    this.$$_hibernate_tracker.add(paramString);
}

因此,解决方案是升级到 Hibernate 5。

于 2016-02-04T13:59:04.827 回答
2

我不知道它是否会在所有情况下为您提供正确的行为,但是您通常可以通过执行以下操作使脏检查正常工作(至少根据我测试过的一些框架代码):

  1. @EntityListeners(YourListener.class)通过添加实体来注册实体侦听器
  2. 将所有@Pre/ @Post(例如@PrePersist等)方法的实现添加到您YourListener.class检查实体是否是 的实例的位置PersistentAttributeInterceptable,以及是否只是使用仅返回新值$$_hibernate_setInterceptor的自定义调用它(该特定行为可能需要针对一般用途进行改进PersistentAttributeInterceptor,我不确定,但在我的简单测试中捕获它就足够了——你比我更了解拦截器的一般用例)。

针对明显是错误的黑客解决方案。

于 2015-06-19T12:43:54.660 回答