Улучшение байт-кода 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
так, чтобы грязные свойства отслеживались методами инструментария байт-кода?
Ответы
Ответ 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
, который просто возвращает новые значения (это конкретное поведение может потребоваться уточнить для общего использования, я не уверен, но это было достаточно хорошо, чтобы поймать его для моих простых тестов - вы знаете больше об общем использовании случаи для перехватчика, чем я).
Решение для взлома, что явно является ошибкой.