我有一个Google App Engine + Java应用程序,它已经运行了很多年(使用JDO +数据存储区进行持久化)并且我没有遇到任何问题(偶尔,并且不情愿地)更新属性手动设置Google Datastore控制台中的实体。
最近(也许是过去的2-3个月)我注意到行为的变化打破了我们的应用程序。我不确切地知道出了什么问题或我们如何处理它。
所以我的问题是: 为什么它的表现不同,我该怎么办呢?
让我首先尝试解释我所看到的行为,然后展示我最小的复制测试用例。
假设您有一个简单的持久化类:
@PersistenceCapable
public class Account implements Serializable {
@Persistent private ShortBlob testShortBlob;
@Persistent private String name;
// ...etc...
}
如果我过去通过数据存储区Web控制台编辑了名称,它将按预期工作,名称字段将更改,其他所有内容都可以正常工作。
我现在看到的行为是,通过控制台保存实体后,我无法再在JDO中查询和加载实体,我得到:
java.lang.ClassCastException: com.google.appengine.api.datastore.Blob cannot be cast to com.google.appengine.api.datastore.ShortBlob
哪些指向某些基础数据存储区更改,这意味着ShortBlob字段正在将其从ShortBlob更改为Blob(即使我没有通过控制台对该字段进行编辑)。
此测试用例将复制该问题:
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
// this one really is a ShortBlob - will load fine in JDO
Entity account = new Entity("Account", "123");
account.setProperty("name", "Test Name");
account.setUnindexedProperty("testShortBlob", new ShortBlob("blah".getBytes()));
datastore.put(account);
// this one really is not a ShortBlob, its a blob - it will fail for the same reason I am seeing in production.
account = new Entity("Account", "124");
account.setProperty("name", "Test Name 2");
account.setUnindexedProperty("testShortBlob", new Blob("blah".getBytes()));
datastore.put(account);
// then load the entity via JDO
try {
accountFromJdo = pm.getObjectById(Account.class, key);
} catch (Exception ex) {
System.out.println("We get here, the object won't load with the ClassCast Exception");
}
这就是问题所在,但为什么通过云数据存储控制台进行保存会将ShortBlob更改为Blob?
我目前的解决方法是在数据存储控制台中将ShortBlob字段设置为null - 然后允许实体加载。但是,如果blob中的数据很重要,那就太糟糕了!
更新
我一直在对此进行更多测试,使用低级JSON API来查看在通过控制台保存实体之前和之后是否可以区分原始JSON响应。好消息是,我可以!
在通过控制台编辑实体之前,通过JDO App Engine界面保存到数据存储区的shortBlob字段将如下所示:
},
"testShortBlob": {
"blobValue": "tNp7MfsjhdfjkahsdvfkjhsdvfIItWyzy6glmIrow4WWhRPbhQ/U+MGX3opVvpxu"
},
但是如果我进入数据存储区控制台并编辑实体(保持blob字段不变,请编辑一个不相关的字段,例如name。现在,当我运行相同的查询时,我得到:
},
"testShortBlob": {
"blobValue": "tNp7MfsjhdfjkahsdvfkjhsdvfIItWyzy6glmIrow4WWhRPbhQ/U+MGX3opVvpxu",
"excludeFromIndexes": true
},
微妙的区别,但我认为这很重要,根据the Java docs ShortBlob
被编入索引,而Blob
则没有。
所以我认为我现在的问题是:为什么通过Cloud Datastore控制台编辑实体会改变blob字段的索引状态?