Java Hibernate 4字节码增强不适用于脏检查优化
我正在使用Hibernate 4.3.6,并且我使用了最新的工具来检测所有实体的自我污染意识 我添加了maven插件:Java Hibernate 4字节码增强不适用于脏检查优化,java,hibernate,orm,byte-code-enhancement,dirty-checking,Java,Hibernate,Orm,Byte Code Enhancement,Dirty Checking,我正在使用Hibernate 4.3.6,并且我使用了最新的工具来检测所有实体的自我污染意识 我添加了maven插件: <build> <plugins> <plugin> <groupId>org.hibernate.orm.tooling</groupId> <artifactId>hibernate-enhance-maven-plugin<
<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>
调试时,我正在检查org.hibernate.event.internal.DefaultFlushentyEventListener#dirtyCheck
方法:
if ( entity instanceof SelfDirtinessTracker ) {
if ( ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes() ) {
dirtyProperties = persister.resolveAttributeIndexes( ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() );
}
}
而$$\u hibernate\u hasDirtyAttributes()
总是返回false
这是因为$\u hibernate\u attributeInterceptor
始终为空,因此在设置任何属性时:
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;
}
由于$$\u hibernate\u getInterceptor()
为空,因此将绕过trackChange,因此字节码增强不会解决脏属性,将使用默认的深度比较算法
我错过了什么?如何正确设置
$\u hibernate\u attributeInterceptor
,以便字节码检测方法跟踪脏属性?我不知道它是否能在所有情况下为您提供正确的行为,但您通常可以使脏检查正常工作(至少根据我测试它的一些基本代码)执行以下操作:
@EntityListeners(YourListener.class)
来注册实体侦听器@Pre
/@Post
添加实现(例如@PrePersist
等)方法,其中检查实体是否是PersistentAttributeInterceptable
的实例,以及是否只是在其上使用仅返回新值的自定义PersistentAttributeInterceptor
调用$\u hibernate\u setInterceptor
(我不确定,这种特殊的行为可能需要改进以用于一般用途,但它足够好,可以在我的简单测试中捕捉到它——你比我更了解拦截器的一般用例)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。是一种字节码增强。您是如何获得类增强程序的源代码的。请遵循问题开头的JIRA问题链接。当我看到您提到的链接时,我看到那些人在编译阶段使用它。您能在编译测试阶段再试一次吗?好的。我将我试着回你电话,因为那篇文章也是我写的;)我更感兴趣的是Hibernate对此的内置支持。你可以自定义脏检查,但这不是我要求的。我想说我只是配置Hibernate以确保增强实体有一个非常简单的拦截器,这是增强代码依赖的。我看不到我在哪里自定义脏检查。这将仍然由$$\u hibernate\u getDirtyAttributes/$$\u hibernate\u hasDirtyAttributes处理,不是吗?正如您指出的,增强的代码需要一个拦截器才能工作。可能有另一种方法配置hibernate来提供拦截器,但通过实体注释提供它只是另一种方法。我不理解您的观点。拦截器不需要处理任何脏检查,就我所知,您可以将其设置为始终返回新值。然后,增强的脏检查可以正常工作。通过通过注释配置一个简单的虚拟拦截器,增强的脏检查可以工作。我想这正是您想要的。否则,这个问题只是一个bug报告:“增强的代码需要一个拦截器——要么它不应该,要么Hibernate应该提供一个伪代码,而不需要通过注释明确地告诉它。”我会测试它并让您知道。嗨,Mihalcea,我正在尝试对我的模型类(在XML映射中)进行字节码增强使用Hibernate 5,但无法转换上述模型类。我是否遗漏了任何内容,或者字节码增强仅适用于注释?据我所知,它也适用于XML映射。我尝试了所有选项,但没有成功。我看到了您的示例,并尝试了相同的方法,但Hibernate 5版本没有成功。奇怪。它可以工作很好。它适用于注释,但不适用于XML映射。我的项目表映射是在XML文件中定义的。
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);
}