记一次troubleshooting
Background:
Oracle升级到19c,保持原有的Hibernate版本不变验证可用性。所以讲测试环境Oracle数据导出,在本地环境安装Oracle 19c导入数据,debug验证。
Issue:
启动报错在transaction.commit();
的代码时:
attempted to assign id from null one-to-one property [com.xxx.xxx]
网上查了很多都是save的时候报错,和我的情况不一样。
Transaction transaction = null;
try {
transaction = getSession().beginTransaction();
String queryString = "from CCxxx as model where model.isActive = true";
Query queryObject = getSession().createQuery(queryString);
queryObject.setCacheRegion(CCXX_CACHE_REGION);
queryObject.setCacheable(true);
List<Currency> ccyList = queryObject.list();
transaction.commit();
return ccyList;
} catch (RuntimeException re) {
transaction.rollback();
throw re;
} finally {
close();
}
Debug代码时发现在org.hibernate.event.def.AbstractSaveEventListener
的getEntityState()
函数的入参entity
为一个所有变量值都为null
的一个POJO。
protected int getEntityState(Object entity, String entityName, EntityEntry entry, SessionImplementor source) {
if (entry != null) {
if (entry.getStatus() != Status.DELETED) {
if (log.isTraceEnabled()) {
log.trace("persistent instance of: " + this.getLoggableName(entityName, entity));
}
return 0;
} else {
if (log.isTraceEnabled()) {
log.trace("deleted instance of: " + this.getLoggableName(entityName, entity));
}
return 3;
}
} else if (ForeignKeys.isTransient(entityName, entity, this.getAssumedUnsaved(), source)) {
if (log.isTraceEnabled()) {
log.trace("transient instance of: " + this.getLoggableName(entityName, entity));
}
return 1;
} else {
if (log.isTraceEnabled()) {
log.trace("detached instance of: " + this.getLoggableName(entityName, entity));
}
return 2;
}
}
导致判断匹配了ForeignKeys.isTransient(entityName, entity, this.getAssumedUnsaved(), source)
遂return 1
。
最终在org.hibernate.id.ForeignGenerator
的generate(SessionImplementor sessionImplementor, Object object)
函数中抛出IdentifierGenerationException
public Serializable generate(SessionImplementor sessionImplementor, Object object) {
Session session = (Session)sessionImplementor;
EntityPersister persister = sessionImplementor.getFactory().getEntityPersister(this.entityName);
Object associatedObject = persister.getPropertyValue(object, this.propertyName, session.getEntityMode());
if (associatedObject == null) {
throw new IdentifierGenerationException("attempted to assign id from null one-to-one property [" + this.getRole() + "]");
} else {
Type propertyType = persister.getPropertyType(this.propertyName);
EntityType foreignValueSourceType;
if (propertyType.isEntityType()) {
foreignValueSourceType = (EntityType)propertyType;
} else {
foreignValueSourceType = (EntityType)persister.getPropertyType("_identifierMapper." + this.propertyName);
}
Serializable id;
try {
id = ForeignKeys.getEntityIdentifierIfNotUnsaved(foreignValueSourceType.getAssociatedEntityName(), associatedObject, sessionImplementor);
} catch (TransientObjectException var10) {
id = session.save(foreignValueSourceType.getAssociatedEntityName(), associatedObject);
}
return session.contains(object) ? IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR : id;
}
}
Solution
究其原因,程序中两个Entity已经配置了<one-to-one>
,所以数据必须一一对应。
检查database中的一个表中缺少了一条数据,发现是由于exp的sql中存在关键字Infinity
,使得在imp的时候报错SQL Error: ORA-00984: column not allowed here
00984. 00000 - “column not allowed here”修正后重新imp。