我正在将遗留的hibernate项目从版本4.3 (使用Java 11)迁移到5.6 (使用Java 16)。下面的HBM文件映射了管辖权-> Unit -> UnitAux的对象图。单位是懒惰加载,UnitAux是一对一的单位.在4.3版下,当初始化单元时,加载大约需要100 to。在5.6版下,它现在需要600到800毫秒。
以下是三个实体的缩写HBM文件:
Jurisdiction.hbm.xml
<hibernate-mapping>
<class name="com.edc.c2c.core.model.impl.Jurisdiction" table="Jurisdiction" schema="domain" dynamic-update="true">
<set name="units"
inverse="true" cascade="all" lazy="true" fetch="select"
optimistic-lock="false" batch-size="1000" where="recordStatus = 'A'">
<key>
<column name="jurisdictionId"/>
</key>
<one-to-many class="com.edc.c2c.core.model.impl.Unit"/>
</set>
</class>
</hibernate-mapping>Unit.hbm.xml
<hibernate-mapping>
<class name="com.edc.c2c.core.model.impl.Unit" table="Unit" schema="domain" dynamic-update="false">
<composite-id>
<key-property name="id" column="id" type="long"/>
<key-property name="owningJurisdictionId" column="jurisdictionId" type="long"/>
</composite-id>
<one-to-one name="unitAux" class="com.edc.c2c.core.model.impl.UnitAux" cascade="all" fetch="join" property-ref="unit"/>
</class>
</hibernate-mapping>UnitAux.hbm.xml
<hibernate-mapping>
<class name="com.edc.c2c.core.model.impl.UnitAux" table="UnitAux" schema="domain" dynamic-update="true">
<composite-id>
<key-property name="id" column="id" type="long"/>
<key-property name="jurisdictionId" column="jurisdictionId" type="long"/>
</composite-id>
<many-to-one name="unit" class="com.edc.c2c.core.model.impl.Unit" unique="true" not-null="true"
cascade="all" insert="false" update="false">
<column name="id"/>
<column name="jurisdictionId"/>
</many-to-one>
</class>
</hibernate-mapping>如果我在Unit.hbm.xml,中注释掉一对一的话,这个单元就会像预期的那样快速加载。
在UnitAux.hbm.xml中,我用一个包含一对多的袋子替换了多对一的,类似这样的东西:
<bag name="unitGroup" inverse="true" cascade="all" lazy="true" fetch="select">
<key>
<column name="id"/>
<column name="jurisdictionId"/>
</key>
<one-to-many class="com.edc.c2c.core.model.impl.unit"/>
</bag>这样,UnitAux类就有了一个名为unitGroup的List属性。随着袋子,单位(S)的装载时间下降到300毫秒。
我不知道如何让hibernate 5.6在与4.3相同的加载时间内执行。
如有任何意见或建议,将不胜感激。
更新:我忘了提到的,这两个版本有效地产生了相同的。有关如何初始化对象本身的内容一定是导致速度减慢的原因。
更新2: 4.3和5.6之间的会话统计数据非常相似;不足以解释性能差异。我的调查显示,延迟似乎集中在初始化实体。特别是,呼吁
Loader.initializeEntitiesAndCollections( final List hydratedObjects, final Object resultSetId, final SharedSessionContractImplementor session, final boolean readOnly, List<AfterLoadAction> afterLoadActions)在这里花费的时间是延迟的所在。每个实体中的每个属性都进行字节码增强测试。在我的测试中,我将加载600+单元以及600+ UnitAux实体。比不做这个的替代加载程序更好吗?
更新3:将单元-> UnitAux的关联更改为单向,减少了大约一半的延迟。现在它只慢了3倍。
更新4: --这很奇怪。在对各种事物进行了实验之后,我做出了如下发现。如果我为hibernate启用了信息(或错误)级别的日志记录(请参见下面的配置),那么一切都会在预期的时间内快速运行:
<logger name="org.hibernate" additivity="false">
<level value="info"/>
<appender-ref ref="STDOUT"/>
</logger>如果未声明日志记录,则运行缓慢(这意味着没有为hibernate专门配置任何内容)。这对jboss来说是很奇怪的吗?我使用的是jboss 3.4.2.final.jar。如果log4j.xml中没有显式声明,它是否运行得更慢?这就像一个典型的问题:调试语句永远不会被使用,但是Java必须构建所有的字符串值,这会导致极大的延迟。
更新5:我刚刚对Hibernate Core5.6.0-Final的源代码进行了抽查。141个类使用log.trace,249个类使用log.debug。大多数log.trace调用都没有预先检查是否启用了跟踪。log.debug调用被检查得更频繁,但是仍然有很多不预先检查是否启用了调试。
发布于 2021-12-22 14:36:27
最后,我找到了自己对这个问题的答案。
首先,Hibernate 5.x和一对一的双向关联根本没有问题.这个问题与调试/跟踪日志记录有关。随着Hibernate 5.x和字节码的增强,增加了许多新的日志记录。不仅对每个逐行实体进行日志记录,而且对每个列/属性(测试列延迟加载?)进行日志记录。
其次,我的实体类对toString()有特殊的格式设置。这些toString()的调用可能需要很长时间才能执行,如果超过数百个实体,则会乘以。
第三,和log4j1-12.x之间一定有一些错误。在内部,jboss#doLogf()检查是否启用了日志记录级别,但是它仍然到达字符串格式化程序。下面是运行在Tomcat中的应用程序的VisualVM快照;您可以看到,为调试格式化添加了700 is,尽管它永远不会打印到日志文件中:

如果Hibernate代码在日志记录调用之前进行了调试/跟踪级别检查,则不会发生这种情况。
最后,使用Tomcat,我删除了所有log4j和slf4jlog4jJAR文件。解决了问题。
https://stackoverflow.com/questions/70279037
复制相似问题