简体   繁体   English

Hibernate 4字节码增强功能不适用于脏检查优化

[英]Hibernate 4 bytecode enhancement not working for dirty checking optimization

I am using the Hibernate 4.3.6 and I made use of the latest Maven bytecode enhancement to instrument all entities for self dirtiness awareness. 我正在使用Hibernate 4.3.6,我利用最新的Maven字节码增强功能来检测所有实体的自我肮脏意识。

I added the maven plugin: 我添加了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>

and I see my entities are being enhanced: 我看到我的实体正在增强:

@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;

  ...

While debugging, I am checking org.hibernate.event.internal.DefaultFlushEntityEventListener#dirtyCheck method: 在调试时,我正在检查org.hibernate.event.internal.DefaultFlushEntityEventListener#dirtyCheck方法:

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

and the $$_hibernate_hasDirtyAttributes() always returns false . 并且$$_hibernate_hasDirtyAttributes()始终返回false

This is because $$_hibernate_attributeInterceptor is always null, so when setting any property: 这是因为$$_hibernate_attributeInterceptor始终为null,因此在设置任何属性时:

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

because the $$_hibernate_getInterceptor() is null the trackChange will be bypassed, hence the bytecode enhancement will not resolve the dirty properties and the default deep-comparison algorithm will be used. 因为$$_hibernate_getInterceptor()为null,所以会绕过trackChange,因此字节码增强不会解析脏属性,并且将使用默认的深度比较算法。

What am I missing? 我错过了什么? How can I get the $$_hibernate_attributeInterceptor to be properly set so that the dirty properties are tracked by the bytecode instrumentation methods? 如何正确设置$$_hibernate_attributeInterceptor ,以便字节码检测方法跟踪脏属性?

Hibernate 5 fixes this issue and now the dirty checking for a setter looks like this: 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);
}

So, the solution is an upgrade to Hibernate 5. 因此,解决方案是升级到Hibernate 5。

I don't know if it will give you the correct behaviour in all situations, but you can generally get the dirty checks working (at least according to some skeleton code I tested it with) by doing the following: 我不知道它是否会在所有情况下都给你正确的行为,但你通常可以通过执行以下操作来使脏检查工作(至少根据我测试过的一些框架代码):

  1. Register an entity listener by adding @EntityListeners(YourListener.class) to the entities 通过将@EntityListeners(YourListener.class)添加到实体来注册实体侦听器
  2. Add implementations for all @Pre / @Post (eg @PrePersist etc) methods to your YourListener.class where you check if the entity is an instance of PersistentAttributeInterceptable , and if it is just call $$_hibernate_setInterceptor on it with a custom PersistentAttributeInterceptor that just returns the new values (that particular behaviour may need refined for general use, i'm not sure, but it was good enough to catch it for my simple tests - you know more about general use cases for the interceptor than me). 将所有@Pre / @Post (例如@PrePersist等)方法的实现添加到YourListener.class ,在那里检查实体是否是PersistentAttributeInterceptable的实例,如果它只是使用自定义PersistentAttributeInterceptor调用$$_hibernate_setInterceptor返回新的值(特定的行为可能需要经过精心处理以供一般使用,我不确定,但是对于我的简单测试来说它已经足够好了 - 你对拦截器的一般用例比我更了解)。

A hack solution for what is clearly a bug. 什么是明显的错误的黑客解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM