gpt4 book ai didi

java - 如何避免使用 Hibernate 从 VARCHAR 到 VARCHAR2 的隐式类型转换?

转载 作者:搜寻专家 更新时间:2023-10-31 20:16:36 25 4
gpt4 key购买 nike

一些同事遇到了一个问题,他们发现查询的执行时间很慢,并且发现由于隐式类型转换而未使用索引。

该表有一个属性 kgb_uuid 用于存储 UUID。该列被定义为 VARCHAR2 并在其上有一个索引以按 UUID 搜索行。

实体中的相关字段定义为String。根据 Hibernate 文档,Hibernate 应将此字符串转换为 Oracle 数据库上的 VARCHAR2,因此应使用索引。

但日志显示情况并非如此:

[9/2/19 11:56:07:610 CEST] 00000177 SystemOut O
2019-09-02T11:56:07,610 TRACE [ebContainer : 3] i.b.e.b.c.TraceInterceptor;log;;41 - entry method [checkEindeutigeUUID] in class [MyDAO] with params (MyEntity@b14745f9)

[9/2/19 11:56:07:688 CEST] 00000177 SQL Z org.hibernate.engine.jdbc.spi.SqlStatementLogger logStatement select count(mytab0_.KGB_NR) as col_0_0_ from MYENTITYTABLE mytab_ where mytab_.KGB_UUID=? and mytab_.EKN_NR=?

[9/2/19 11:56:07:688 CEST] 00000177 BasicBinder Z org.hibernate.type.descriptor.sql.BasicBinder bind binding parameter [1] as [VARCHAR] - 795BF3B98D879358E0531C03A90ABF0A [9/2/19 11:56:07:688 CEST] 00000177 BasicBinder Z org.hibernate.type.descriptor.sql.BasicBinder bind binding parameter [2] as [BIGINT] - 1

如所见,字符串值绑定(bind)为 VARCHAR 而不是 VARCHAR2,导致数据库进行隐式类型转换而不使用索引,如 OEM 中所示(这是来自 OEM 的原始德语消息):

Das Prädikat SYS_OP_C2C("mytab_"."KGB_UUID")=:B1, das in Zeilen-ID 3 des Ausführungsplans benutzt wird, enthält eine Konvertierung des impliziten Datentyps auf der indexierten Spalte "KGB_UUID". Diese Konvertierung des impliziten Datentyps verhindert, dass der Optimizer Indizes auf Tabelle "MYENTITYTABLE" effizient nutzt.

它表示使用了谓词 SYS_OP_C2C("mytab_"."KGB_UUID")=:B1 并且它包含索引基列 KGB_UUID< 的隐式属性类型的对话 并且这种隐式类型的对话会阻止优化器有效地使用表 MYENTITYTABLE 的索引。

我们已经解决了在表上使用函数索引的问题,但我们仍然想知道为什么 Hibernate 提供的数据类型显然不是 VARCHAR2

系统:

  • Hibernate 4.2.21 与 Hibernate Dialect Oracle10g(根据文档最多兼容 12 个)
  • Oracle 12.2(现在不完全是,我认为是 12.2,但可能只有 12.1)

Hibernate 版本无法升级,因为它是可与 JPA 2.0 一起使用的最后一个版本,JPA 2.0 是 Websphere Process Server 8.5 支持的 JavaEE 6 的一部分。

(简称)实体

@Entity
@Table(name = "MYENTITYTABLE")
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;

@Id
// out commented the sequence generator
@Column(name="KGB_NR")
private long kgbNr;

@Column(name="KGB_UUID")
private String kgbUuid; // <<== DEFINED AS STRING!

//bi-directional many-to-one association to Ekistnutzer
@ManyToOne
@JoinColumn(name="EKN_NR")
private EkistnutzerEntity ekistnutzer;

// Other attributes not related in problem
}

DAO 方法

public int checkEindeutigeUUID(MyEntity myEntity) throws Exception {

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
ParameterExpression<String> kgbUuidParam = criteriaBuilder.parameter(String.class, "kgbUuid");
ParameterExpression<EkistnutzerEntity> ekistnutzerParam = criteriaBuilder.parameter(EkistnutzerEntity.class,
"ekistnutzer");
Root<MyEntity> root = query.from(MyEntity.class);
query.select(criteriaBuilder.count(root));
query.where(criteriaBuilder.equal(root.get("kgbUuid"), kgbUuidParam),
criteriaBuilder.equal(root.get("ekistnutzer"), ekistnutzerParam));

try {
TypedQuery<Long> typedQuery = entityManager.createQuery(query);
typedQuery.setParameter("ekistnutzer", myEntity.getEkistnutzer());
typedQuery.setParameter("kgbUuid", myEntity.getKgbUuid());

return typedQuery.getSingleResult().intValue();
} catch (Exception e) {
throw e;
}
}

最佳答案

最简单的方法是扩展默认的 StringType并覆盖 sqlType属性并通过 @Type 将新的 Hibernate Type 提供给您的实体属性注释。

很可能是 VARCHAR2映射来自 Oracle Hibernate 方言,因此您可能不应该覆盖默认的方言映射,因为可能有列正确使用 VARCHAR2 .

因此,自定义 Hibernate 类型为您提供了控制权,并允许您仅将其用于 VARCHAR列。

关于java - 如何避免使用 Hibernate 从 VARCHAR 到 VARCHAR2 的隐式类型转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57934045/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com