0

大家,我有以下代码,它适用于多个测试系统,但在生产系统上失败,带有NullPointerException. Hibernate 为肯定在数据库中的对象返回 null。我认为这可能是由于交易管理不善,但我不确定。有人看到问题吗?下面的代码都使用了一个 Hibernate 包装对象,'db'。创建“db”时,从 Hibernate 的会话工厂创建了一个新的 Session,因此只有下面显示的我的代码使用该 Session。

从 Request 表中获取所有有效 ID 的列表。ID 是主键字段:

Criteria criteria = db.getSession().createCriteria(Request.class);
Criterion crit = Restrictions.and(Restrictions.eq("status", "valid"));
criteria.add(crit).setProjection(Projections.property("id"));
List<Integer> results = (List<Integer>)criteria.list();
List<Integer> idList = new ArrayList<Integer>();
for (Integer id : results) idList.add(id);

下面的代码是引发 NullPointerException 的原因。请参阅 catch 块中的代码注释。辅助方法如下所示:

for (Integer id : idList){
   Request current = null;
   try{
      current = (Request) db.getObj(Request.class, Restrictions.eq("id", id));
      // ... other business logic in here
      InvalidRequest newInvalidRequest = new InvalidRequest(current.getId(), current);
      db.addObject(newInvalidRequest);
    }
    } catch (Exception e){
       //This Exception gets thrown and caught. However the log message never prints.
       //Further along in the code, I get a NullPointerException because
       //the variable 'current' was null and therefore I can't call current.getId()
       //(which is why the log message never printed).
       //but how could current be null when 'id' is in the Request table?
       Log.error("ID = " + current.getId(), e);
    }
}

辅助方法:

public <T> Object getObj(Class<T> clazz, Criterion crit) throws Exception {
   Object object = null;
   try {
      object = session.createCriteria(clazz).add(crit).uniqueResult();
   } catch (Exception e) {
      throw new Exception(e);
   }
   return object;
}

public <T> void addObject(T object) throws Exception {
    try {
        Transaction trans = session.beginTransaction();
        session.save(object);
        trans.commit();
    } catch (Exception e) {
        throw new Exception(e);
    }
}

一些注意事项:

  • InvalidRequest 对象是一个 Hibernate 对象,它与 Request 对象具有一对一的外键关系。换句话说,这就是为什么当我创建一个新的 InvalidRequest 时,我将 Request 作为参数传入。
  • addObject 方法使用 Transaction 但 getObj 不使用。我不知道这对我的问题是否有任何特殊意义,但这只是一个注释。
  • 你会注意到我从未在 Request 对象上使用过 evict() 或任何东西。我认为这意味着 Hibernate 将它们存储在会话缓存中一段时间​​。这是否使我有可能内存不足?或者如果缓存太大,Hibernate 会自动为我清除缓存吗?无论哪种方式,我都认为这不是问题,因为我的代码很快就被炸毁了,但我并不积极。
4

1 回答 1

0

这是一个旧的,但当我偶然发现它时,它仍然是 Hibernate 3 的未公开问题。

休眠标准中的投影与 LockMode 不兼容,请参阅https://hibernate.atlassian.net/browse/HHH-3313 ,因此请检查您可能拥有的代码

criteria.setLockMode(your lock mode)

如果像我们一样,您在这里使用一些通用代码来初始化您的标准,我们的代码提取来处理这个问题

CriteriaImpl critiml = (CriteriaImpl) crit;
if (critiml.getProjection() != null) {
    // lock mode is not compatible with projection criteria 
    // see bug entry https://hibernate.onjira.com/browse/HHH-3313
} else {
    crit.setLockMode("obj", LockMode.NONE);
}
于 2015-10-27T10:12:37.313 回答