我一直在使用我自己的对象缓存,它或多或少有效:
现在这在大多数情况下运行良好,但在某些情况下会导致一些不需要的数据库命中。我发现了以下情况:
此时hibernate意识到,该对象是'dettached',并且在nullify检查期间,它再次从数据库中获取该对象。
有没有办法避免这种情况?我是否可以在不访问数据库的情况下将对象重新附加到会话中? “相信我hiberante,这是一个有效的对象,请记住它”。
下面我附上这种情况的堆栈跟踪。
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 :(得分:1)
我可以使用以下丑陋的黑客来避免在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]);
答案 1 :(得分:0)
Hibernate
有Session.merge(Object)
merge这样做。
但考虑转移到二级缓存Ehcache是免费且好的。可在内存缓存中高度配置。
您还应该考虑long conversation pattern,因为它看起来符合您的需求。
答案 2 :(得分:0)
您可以避免往返,因为owner
上的Car
字段不是实体,而是int / long字段。使用它更加繁琐,但你确定数据库没有被击中。设置它看起来像这样:
car.setOwnerId(cache.lookup("Pete").getId())
当然,你失去了直接访问实体的优势。