如何 HQL 查询没有 Id 的项目?

时间:2021-03-26 15:42:41

标签: java hibernate hql

我的数据库中有大量数据,我决定迁移到 Hibernate。我的一张桌子(我们称之为“MyItem”)没有任何合适的 ID。它只包含一列“json”。

由于某种原因(与数据量有关),我无法迁移所有 MyItem 数据,因此它们都有一个新的唯一标识符。

我所做的是向该表添加一个新的“标识符”列(因此有两列:“json”和“标识符”),并在我的 Java 代码中声明了我的实体,使其看起来像这样:

@Entity
@Table
public class MyItem {
    @Lob
    private String json;

    private String identifier;

    public MyItem() {
    }

    public MyItem(String json) {
        this.json = json;
    }

    public void setIdentifier(String id) {
        //fake
    }

    @Id
    public String getIdentifier() {
        if (identifier == null) {
            identifier = UUID.randomUUID().toString();
        }
        return identifier;
    }
    
    public String getJson() {
        return json;
    }
    
    public void setJson(String json) {
        this.json = json;
    }
}

我可以正确创建和访问我的新数据(新数据是用 Id 生成的),但只有当我通过 HQL 访问最旧的数据(标识符列中为 null 的数据)时,我才难以访问。

这是我执行查询的方式(当然,我已经为问题更改了一些内容,请忽略我的假“""json"",当然它不是 json,只是示例):

String myJson = "6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1";
Query<MyItem> query = statelessSession.createQuery("FROM MyItem WHERE json = :json", MyItem.class);
query.setParameter("json", myJson);
query.setFetchSize(FETCH_SIZE);
query.setReadOnly(true);
query.setLockMode("a", LockMode.NONE);
try (ScrollableResults MyItemList = query.scroll(ScrollMode.FORWARD_ONLY)) {
    while (MyItemList.next()) {
        MyItem myItem = (MyItem) MyItemList.get(0);
        myItem.getJson());
    }
}

我在 myItem.getJson() 上得到了一个 NPE;

这里是 Hibernate 跟踪:

14:55:58.263 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.QueryPlanCache@157 - Located HQL query plan in cache (FROM MyItem WHERE json = :json) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.QueryPlanCache@157 - Located HQL query plan in cache (FROM MyItem WHERE json = :json) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.query.spi.HQLQueryPlan@344 - Iterate: FROM MyItem WHERE json = :json 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.j.i.AbstractLogicalConnectionImplementor@66 - Preparing to begin transaction via JDBC Connection.setAutoCommit(false) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.engine.spi.QueryParameters@325 - Named parameters: {json=6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1} 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.j.i.AbstractLogicalConnectionImplementor@68 - Transaction begun via JDBC Connection.setAutoCommit(false) 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] TRACE o.h.r.t.b.j.i.JdbcResourceLocalTransactionCoordinatorImpl@172 - ResourceLocalTransactionCoordinatorImpl#afterBeginCallback 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.h.e.t.internal.TransactionImpl@56 - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] DEBUG org.hibernate.SQL@94 - 
 select 
 myit0_.identifier as identifi1_0_,
 myit0_.json as json5_0_
 from 
 MyItem myit0_ 
 where 
 myit0_.json=? 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.h.e.t.internal.TransactionImpl@78 - begin 
14:55:58.264 [TileBuilderCallable_pool-11-thread-3] DEBUG o.s.j.d.DriverManagerDataSource@144 - Creating new JDBC DriverManager Connection to [jdbc:com.db://localhost:1234/mydb] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.r.j.i.ResourceRegistryStandardImpl@68 - Registering statement [[Statement - handle 1 (Connection ID - 25769822844)]] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.e.j.internal.JdbcCoordinatorImpl@339 - Registering last query statement [[Statement - handle 1 (Connection ID - 25769822844)]] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.type.descriptor.sql.BasicBinder@65 - binding parameter [1] as [VARCHAR] - [6044c44a-dd17-40ca-b66b-cb9d29cf8a33-1-0-1] 
14:55:58.264 [TileBuilderCallable_pool-11-thread-2] TRACE org.hibernate.loader.Loader@2034 - Bound [2] parameters total 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.r.j.i.ResourceRegistryStandardImpl@196 - Registering result set [com.db.ResultSet@55612811] 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] TRACE o.h.t.descriptor.sql.BasicExtractor@51 - extracted value ([identifi1_0_] : [VARCHAR]) - [null] 
14:55:58.266 [TileBuilderCallable_pool-11-thread-2] DEBUG org.hibernate.loader.Loader@1532 - Result row: null 
14:55:58.267 [TileBuilderCallable_pool-11-thread-2] TRACE org.hibernate.loader.Loader@1149 - Total objects hydrated: 0

我在这里唯一的想法是尝试/捕获 NPE,因此我通过添加标识符来动态迁移数据。还有其他更智能的方法来执行我的查询吗?

谢谢! :)

1 个答案:

答案 0 :(得分:0)

  1. 这看起来很可疑:
public void setIdentifier(String id) {
  //fake
}

为什么不在这里设置 identifier 字段?尝试将其更正为:

public void setIdentifier(String id) {
  this.identifier = id;
}

并重新检查您的问题。

  1. 您试图混淆可能导致问题的 access strategies。默认情况下,@Id 注释的位置提供默认访问策略。当放置在一个字段上时,Hibernate 将承担基于字段的访问。当放置在标识符 getter 上时,Hibernate 将使用基于属性的访问。 因此,当您使用基于属性的访问时,hibernate 将忽略您的 @Lob 注释。

  2. 您对 getIdentifier 方法的实现看起来也很可疑。我建议您使用 @GeneratedValue 来生成实体 ID。 Hibernate 支持 UUID identifier value generation

因此,我建议您以这种方式更正映射:

import org.hibernate.annotations.Type;

@Entity
@Table
public class MyItem {

  @Id
  @GeneratedValue
  @Type(type = "uuid-char")
  private UUID identifier;
  
  @Lob
  private String json;

  // ...

  @Transient
  public String getIdentifierAsString() {
     return identifier != null ? identifier.toString() : null;
  }
}
相关问题