2012-03-15 13 views
0

分離オブジェクトをキャッシュされた: Hibernateは、私は、多かれ少なかれ働く私自身のオブジェクト・キャッシュを使用してきた

  • (ログイン名によって、例えば、使用のための)固定基準でオブジェを取得

    1. でオブジェクトストアを
    2. 別のセッションで同じオブジェクトが再び要求された場合、同じオブジェクトを再度使用します。
    3. オブジェクトは非常に稀にしか変更されず、極端に頻繁に使用されます(読み取り専用)。何かがデータベースで変更された場合、私はオブジェクトキャッシュをクリアするフックを持っています。

    これはほとんどの状況ではうまくいきますが、場合によっては望ましくないデータベースヒットを引き起こします。私はオブジェクトを作成

    • (新しいカー())
    • は、このオブジェクトにキャッシュされたオブジェクトを割り当てます:car.setOwner(cache.lookup( "ピート"))(この私は、次のような状況を認識していますオブジェクトは、その後、私はオブジェクト

    は、この時点で、Hibernateはそのオブジェクトが「dettached」とNULLIFYの間にそれから、そのオブジェクトをフェッチチェックされていることを、実現保存

  • )20分前に別のセッションでは、データベースからフェッチされましたもう一度データベースを開きます。

    これを避ける方法はありますか?データベースにアクセスせずにオブジェクトをセッションに再接続することはできますか? "私はhiberanteを信頼して、これは有効なオブジェクトです、それを覚えてください"。

    以下、この状況のスタックトレースを添付します。

    休止バージョン: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中にそのunnecessarryデータベースヒットを避けることができました。

    このトピックは、関連するトピックやパーツに関する豊富な研究を必要とせずに使用しないでください。私たちの場合、空のリストを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がそうしなければなりません。

    しかし、レベル2のキャッシュに移動することを検討してください。Ehcacheは無料でいいです。メモリキャッシュに高度に設定可能。

    long conversation patternは、あなたのニーズに合った見た目であると考えてください。

    +0

    マージもdatabseにヒットしますか?答えのために – reto

    0

    ownerフィールドをCarにエンティティとしてではなく、int/longフィールドとして使用することで、ラウンドトリップを回避できます。これで作業するのは面倒ですが、データベースがヒットしていないことを確認できます。設定すると、次のようになります。

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

    もちろん、エンティティに直接アクセスできるという利点はありません。

    +0

    ありがとう。しかし、それはペットとして猫を飼っていないという猫の問題で猫の所有者に伝えるのが好きです:)。 – reto

    +0

    しかし、真剣に、私は簡単に非休止状態の解決策に落ちることができないこのような問題で。 – reto

    関連する問題