Подтвердить что ты не робот

Улучшение байт-кода Hibernate 4 не работает для оптимизации контроля за грязью

Я использую 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 всегда имеет значение 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;
}

потому что $$_hibernate_getInterceptor() имеет значение null, trackChange будет обходить, поэтому усиление байткода не решит грязные свойства, и будет использоваться алгоритм глубокого сравнения по умолчанию.

Что мне не хватает? Как я могу правильно настроить $$_hibernate_attributeInterceptor так, чтобы грязные свойства отслеживались методами инструментария байт-кода?

4b9b3361

Ответ 1

Hibernate 5 исправляет эту проблему, и теперь грязная проверка для сеттера выглядит следующим образом:

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.

Ответ 2

Я не знаю, даст ли он правильное поведение во всех ситуациях, но вы можете обычно выполнять грязные проверки (по крайней мере, согласно некоторому скелетному коду, с которым я его тестировал), выполнив следующее:

  • Зарегистрируйте прослушиватель объектов, добавив @EntityListeners(YourListener.class) к сущностям
  • Добавьте к вашим YourListener.class реализации для всех методов @Pre/@Post (например, @PrePersist и т.д.)), где вы проверяете, является ли объект экземпляром PersistentAttributeInterceptable, и если это просто вызов $$_hibernate_setInterceptor на нем с пользовательским PersistentAttributeInterceptor, который просто возвращает новые значения (это конкретное поведение может потребоваться уточнить для общего использования, я не уверен, но это было достаточно хорошо, чтобы поймать его для моих простых тестов - вы знаете больше об общем использовании случаи для перехватчика, чем я).

Решение для взлома, что явно является ошибкой.