2017-07-21 30 views
0

我正在嘗試Spring Boot和Hibernate Second Level Caching。我成功地實現了它的工作。然而,如果ID列是一個VARCHAR,我不能從第二級緩存中獲取實體。下面是相關的類:如果ID列是VARCHAR,Hibernate不會從第二級緩存中獲取

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) 
@Table(name = "user1") 
@Entity 
public class User { 
    private long userId; 
    private String name; 

    @Id 
    @Column(name = "id") 
    public long getUserId() { 
     return userId; 
    } 

    public void setUserId(long userId) { 
     this.userId = userId; 
    } 

    @Column(name = "name") 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public User(String name) { 
     this.name = name; 
    } 

    public User() { 
    } 
} 

這個實體工作得很好,這裏有從休眠狀態的調試日誌第一和第二取

取1

o.h.e.t.internal.TransactionImpl   : begin 
org.hibernate.SQL      : select user0_.id as id1_1_0_,  user0_.name as name2_1_0_ from user1 user0_ where user0_.id=? 
o.h.l.p.e.p.i.ResultSetProcessorImpl  : Starting ResultSet row #0 
l.p.e.p.i.EntityReferenceInitializerImpl : On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified 
o.h.engine.internal.TwoPhaseLoad   : Resolving associations for [com.voyant.master.entities.User#1] 
o.h.engine.internal.TwoPhaseLoad   : Adding entity to second-level cache: [com.voyant.master.entities.User#1] 
o.h.engine.internal.TwoPhaseLoad   : Done materializing entity [com.voyant.master.entities.User#1] 
o.h.r.j.i.ResourceRegistryStandardImpl : HHH000387: ResultSet's statement was not registered 
.l.e.p.AbstractLoadPlanBasedEntityLoader : Done entity load : com.voyant.master.entities.User#1 
o.h.e.t.internal.TransactionImpl   : committing 

取2

o.h.e.t.internal.TransactionImpl   : begin 
o.h.e.t.internal.TransactionImpl   : committing 

現在,有問題的實體定義:

@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) 
@Table(name = "user") 
@Entity 
public class User2 { 

    @Id 
    @Column(name = "username") 
    private String username; 

    @Column(name = "lastname") 
    private String lastname; 

    @Column(name = "name") 
    private String name; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getLastname() { 
     return lastname; 
    } 

    public void setLastname(String lastname) { 
     this.lastname = lastname; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public User2(String name) { 
     this.name = name; 
    } 

    public User2() { 
    } 
} 

休眠從同一實體

的兩個連續取調試日誌取1

o.h.e.t.internal.TransactionImpl   : begin 
o.h.jpa.criteria.CriteriaQueryImpl  : Rendered criteria query -> select generatedAlias0 from User2 as generatedAlias0 where generatedAlias0.username=:param0 
org.hibernate.SQL      : select user2x0_.username as username1_0_, user2x0_.lastname as lastname2_0_, user2x0_.name as name3_0_ from user user2x0_ where user2x0_.username=? 
org.hibernate.loader.Loader    : Result set row: 0 
org.hibernate.loader.Loader    : Result row: EntityKey[com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Resolving associations for [com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Adding entity to second-level cache: [com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Done materializing entity [com.voyant.master.entities.User2#dharam] 
o.h.e.t.internal.TransactionImpl   : committing 
o.h.e.i.AbstractFlushingEventListener : Processing flush-time cascades 
o.h.e.i.AbstractFlushingEventListener : Dirty checking collections 
o.h.e.i.AbstractFlushingEventListener : Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects 
o.h.e.i.AbstractFlushingEventListener : Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections 
o.hibernate.internal.util.EntityPrinter : Listing entities: 
o.hibernate.internal.util.EntityPrinter : com.voyant.master.entities.User2{name=dharam, username=dharam, lastname=dharam} 

取2

o.h.e.t.internal.TransactionImpl   : begin 
o.h.jpa.criteria.CriteriaQueryImpl  : Rendered criteria query -> select generatedAlias0 from User2 as generatedAlias0 where generatedAlias0.username=:param0 
org.hibernate.SQL      : select user2x0_.username as username1_0_, user2x0_.lastname as lastname2_0_, user2x0_.name as name3_0_ from user user2x0_ where user2x0_.username=? 
org.hibernate.loader.Loader    : Result set row: 0 
org.hibernate.loader.Loader    : Result row: EntityKey[com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Resolving associations for [com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Adding entity to second-level cache: [com.voyant.master.entities.User2#dharam] 
o.h.engine.internal.TwoPhaseLoad   : Done materializing entity [com.voyant.master.entities.User2#dharam] 
o.h.e.t.internal.TransactionImpl   : committing 
o.h.e.i.AbstractFlushingEventListener : Processing flush-time cascades 
o.h.e.i.AbstractFlushingEventListener : Dirty checking collections 
o.h.e.i.AbstractFlushingEventListener : Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects 
o.h.e.i.AbstractFlushingEventListener : Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections 
o.hibernate.internal.util.EntityPrinter : Listing entities: 
o.hibernate.internal.util.EntityPrinter : com.voyant.master.entities.User2{name=dharam, username=dharam, lastname=dharam} 
+0

可以請你改變你的用戶類工具可串行化,看看它是否工作。 ********* public class User實現Serializable { – user8271644

+0

抱歉!用戶類都很好。問題與User2類,但是!我會嘗試你的建議。 – dharam

+0

道歉我指的是有問題的人。 – user8271644

回答

0

我能夠弄清楚這個問題,因此在這裏做一個日誌,這樣如果有人在將來面臨這個問題,它可能會證明是一個節省時間的方法。我們知道二級緩存在ID列上(ID可以是字符串,整數,長整型等)工作。這隻適用於使用findOne(id)方法來獲取對象。

如果您有任何機會在存儲庫中定義了findByUsername(String username)方法並使用它來獲取實體,則會將其緩存。但是,第二次獲取甚至不願意從緩存中進行查詢。

相關的代碼是RepositoryFactorySupport.QueryExecutorMethodInterceptor.doInvokce()方法。在這裏你可以清楚地看到如下:

Method method = invocation.getMethod(); 
Object[] arguments = invocation.getArguments(); 

if (isCustomMethodInvocation(invocation)) { 

    Method actualMethod = repositoryInformation.getTargetClassMethod(method); 
    return executeMethodOn(customImplementation, actualMethod, arguments); 
} 

if (hasQueryFor(method)) { 
    return queries.get(method).execute(arguments); 
} 

// Lookup actual method as it might be redeclared in the interface 
// and we have to use the repository instance nevertheless 
Method actualMethod = repositoryInformation.getTargetClassMethod(method); 
return executeMethodOn(target, actualMethod, arguments); 

有根據條件三個代碼路徑:

  1. 如果有一個自定義的方法調用
  2. 如果該方法
  3. 查詢
  4. 或者這是一種實際的方法。

課學到如果有一個ID定義,使用基於的ID查詢框架方法,不寫自定義好看的方法:)

相關問題