java hibernate orm byte-code-enhancement dirty-checking

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:

  1. Registre un oyente de entidad agregando @EntityListeners(YourListener.class) a las entidades
  2. Añada implementaciones para todos los @Pre / @Post (por ejemplo, @PrePersist etc.) a su YourListener.class donde puede verificar si la entidad es una instancia de PersistentAttributeInterceptable , y si solo se trata de llamar a $$_hibernate_setInterceptor con un PersistentAttributeInterceptor 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.