2012-03-15 24 views
0

我一直在用自己的对象缓存,其作品或多或少:(通过登录名,例如使用)由固定标准Hibernate的缓存分离对象

  1. GET OBJET
  2. 存放在该对象hashmap,因为它一遍又一遍地被使用
  3. 如果在另一个会话中再次请求同一个对象,我再次使用同一个对象。
  4. 我的对象变化非常大,并经常使用极端(只读)。如果在数据库中有任何更改,我有挂钩清除我的对象缓存。

现在,在大多数情况下这种方式非常好,但在某些情况下会导致一些不需要的数据库命中。我已经确定了以下情况:

  • 我创建一个对象(新车())
  • 缓存对象分配给这个对象:car.setOwner(cache.lookup( “皮特”))(此对象是从数据库中另一个会话获取19分钟前)
  • 然后我保存对象

此时休眠实现,即该对象是“独栋”,并在废止检查获取该对象从数据库再次。

有没有办法避免这种情况?我可以在不碰到数据库的情况下将对象重新附加到会话中吗? “相信我吧,这是一个有效的对象,请记住它”。

下面我附上了这种情况的堆栈跟踪。

Hibernate的版本:3.3.2.GA

干杯 雷托

org.hibernate.jdbc.util.SQLStatementLogger.logStatement(SQLStatementLogger.java:115) 
org.hibernate.jdbc.AbstractBatcher.log(AbstractBatcher.java:444) 
org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:511) 
org.hibernate.jdbc.AbstractBatcher.prepareSelectStatement(AbstractBatcher.java:145) 
org.hibernate.persister.entity.AbstractEntityPersister.getDatabaseSnapshot(AbstractEntityPersister.java:1034) 
org.hibernate.engine.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:269) 
org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:212) 
org.hibernate.engine.ForeignKeys$Nullifier.isNullifiable(ForeignKeys.java:160) 
org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:92) 
org.hibernate.engine.ForeignKeys$Nullifier.nullifyTransientReferences(ForeignKeys.java:70) 
org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:311) 
org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) 
org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144) 
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) 
org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) 
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) 
org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) 
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 
org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:563) 
org.hibernate.impl.SessionImpl.save(SessionImpl.java:551) 
org.hibernate.impl.SessionImpl.save(SessionImpl.java:547) 
sun.reflect.GeneratedMethodAccessor271.invoke (Unknown Source) 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessor 

回答

0

我在isNullifiable/isTransient中使用以下丑陋的黑客手段避免了不必要的数据库命中。

如果没有深入研究相关主题/部分,请不要使用它。在我们的例子中,将空List添加到snapshotHash是没有问题的,但在另一种情况下,这可以完全不同。

/* lets say I know that this oject was from another session */ 
Object object = ... 

/* extract SessionImpl from session */ 

InvocationHandler invocationHandler = Proxy.getInvocationHandler(rawSess); 
Field f = invocationHandler.getClass().getDeclaredField("realSession"); 
f.setAccessible(true); 
SessionImpl sessImpl = (SessionImpl) f.get(invocationHandler); 

/* now extract the entitySnapshotsByKey from the used persistence context */ 
PersistenceContext pc = sessImpl.getPersistenceContext(); 

    Field field = StatefulPersistenceContext.class.getDeclaredField("entitySnapshotsByKey"); 
field.setAccessible(true); 

Map<Object, Object> entitySnapshotsByKey = (Map) field.get(pc); 

/* get the internal metadata about that entity */ 
String entityName = object.getClass().toString(); 
EntityPersister persister = sessImpl.getEntityPersister(entityName, object); 
Serializable id = persister.getIdentifier(object, sessImpl.getEntityMode()); 

EntityKey key = new EntityKey(id, persister, sessImpl.getEntityMode()); 

/* add an empty list, as the content isnt used in our case */ 
entitySnapshotsByKey.put(key, new Object[0]); 
0

HibernateSession.merge(Object)merge这样做。

但考虑搬到二级缓存Ehcache是免费的,很不错。高度可配置在内存缓存中。

你也应该考虑long conversation pattern,因为它看起来符合你的需求。

+0

merge也碰到数据库,不是吗? – reto 2012-03-15 10:42:56

0

您可以通过将Carowner字段作为实体,而不是作为int/long字段来避免往返。处理这件事情更乏味,但你一定要确保数据库没有被击中。设置它看起来像这样:

car.setOwnerId(cache.lookup("Pete").getId()) 

当然,你失去了直接访问与实体的优势。

+0

感谢您的答案。但是喜欢告诉猫主人猫的问题不要把猫当宠物:)。 – reto 2012-03-15 13:48:27

+0

但严重的是,有了这样的问题,我可以轻松地回退到非休眠解决方案。 – reto 2012-03-15 13:49:12