I'm in a situation where I had a LOT of data in my DB, and I decided to move to Hibernate. One of my tables (let's call it "MyItem") didn't have any suitable Id. It contained only one column, 'json'.
For some reason (related to the quantity of data), I could not migrate all the MyItem data so they all have a new unique identifier.
What I did was to add a new 'identifier' column to this table (so two columns: 'json' and 'identifier'), and in my Java code I declared my entity so that it looks like this:
@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;
}
}
I can create and access my new data correctly (new ones are generated with an Id), but I am struggling accessing the oldest one (those having null in their identifier column) only when I do it through HQL.
Here is the way I perform my query (of course, I have changed some stuffs for the question, please disregard my fake ""json"", of course it's not json, it's just for the example):
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());
}
}
And I get a NPE on the myItem.getJson();
Here are Hibernate traces:
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
The only idea I have here is to try/catch the NPE so I migrate the data on the fly by adding an identifier. Is there any other smarter way to perform my query?
Thanks: :)
public void setIdentifier(String id) {
//fake
}
Why you do not set the identifier
field here? Try to correct it to this:
public void setIdentifier(String id) {
this.identifier = id;
}
and recheck your problem.
You are trying to mix up access strategies what can lead to problems. By default, the placement of the @Id
annotation gives the default access strategy. When placed on a field, Hibernate will assume field-based access. When placed on the identifier getter, Hibernate will use property-based access. So, hibernate will ignore your @Lob
annotation, as you use property-based access.
Your implementation of the getIdentifier
method also looks suspicious. I would suggest you to use @GeneratedValue
for the entity id generation. Hibernate supports UUID identifier value generation .
So, I would suggest you to correct your mapping in this way:
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;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.