java - La mejora del código de bytes de Hibernate 4 no funciona para la optimización de comprobación sucia
orm byte-code-enhancement (2)
Estoy usando Hibernate 4.3.6 e hice uso de la última mejora de código de bytes de Maven para instrumentar a todas las entidades para la auto conciencia de suciedad.
Agregué el 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>
y veo que mis entidades se están mejorando:
@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;
...
Mientras estoy depurando, estoy comprobando org.hibernate.event.internal.DefaultFlushEntityEventListener#dirtyCheck
método org.hibernate.event.internal.DefaultFlushEntityEventListener#dirtyCheck
:
if ( entity instanceof SelfDirtinessTracker ) {
if ( ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes() ) {
dirtyProperties = persister.resolveAttributeIndexes( ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() );
}
}
y el $$_hibernate_hasDirtyAttributes()
siempre devuelve falso .
Esto se debe a que $$_hibernate_attributeInterceptor
siempre es nulo, por lo que al configurar cualquier propiedad:
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;
}
debido a que $$_hibernate_getInterceptor()
es nulo, el TrackChange se omitirá, por lo tanto, la mejora de bytecode no resolverá las propiedades sucias y se usará el algoritmo de comparación profunda predeterminado.
¿Qué me estoy perdiendo? ¿Cómo puedo hacer que $$_hibernate_attributeInterceptor
se establezca correctamente para que las propiedades sucias sean rastreadas por los métodos de instrumentación bytecode?
No sé si te dará el comportamiento correcto en todas las situaciones, pero en general puedes hacer que los cheques sucios funcionen (al menos de acuerdo con algún código de esqueleto con el que lo probé) haciendo lo siguiente:
- Registre un oyente de entidad agregando
@EntityListeners(YourListener.class)
a las entidades - Añada implementaciones para todos los
@Pre
/@Post
(por ejemplo,@PrePersist
etc.) a suYourListener.class
donde puede verificar si la entidad es una instancia dePersistentAttributeInterceptable
, y si solo se trata de llamar a$$_hibernate_setInterceptor
con unPersistentAttributeInterceptor
personalizado que solo devuelve los nuevos valores (ese comportamiento en particular puede necesitar refinamiento para uso general, no estoy seguro, pero fue lo suficientemente bueno como para atraparlo para mis pruebas simples; usted sabe más sobre casos de uso general para el interceptor que yo).
Una solución de pirateo para lo que es claramente un error.
Hibernate 5 soluciona este problema y ahora la comprobación sucia de un setter se ve así:
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);
}
Entonces, la solución es una actualización a Hibernate 5.