2017-03-06 63 views
3

我使用Hibernate 5.2.5(如果有問題,也可以使用kotlin和spring 4.3.5),我希望我的類的某些字段能夠被加載。但問題是所有字段都立即加載,我沒有任何特殊的Hibernate設置,都沒有使用Hibernate.initialize()。休眠忽略'lazy'提取類型並立即加載屬性

@Entity(name = "task") 
@Table(name = "tasks") 
@NamedQueries(
     NamedQuery(name = "task.findById", query = "SELECT t FROM task AS t WHERE t.id = :id") 
) 
class Task { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    var id: Int? = null 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "author_id", nullable = false) 
    lateinit var author: User 

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "task") 
    var edit: TaskEdit? = null 
} 

這是我的查詢

TaskRepoImpl:

override fun findById(id: Int): Task? { 
    val task = getCurrentSession().createNamedQuery("task.findById", Task::class.java) 
      .setParameter("id", id) 
      .uniqueResult() 
    return task 
} 

TaskService:

@Transactional 
fun find(id: Int): Task? { 
    return taskRepo.findById(id) 
} 

和輸出:

Hibernate: select task0_.id as id1_1_, task0_.author_id as author_i3_1_ from tasks task0_ where task0_.id=? 
Hibernate: select user0_.id as id1_3_0_, user0_.enabled as enabled2_3_0_, user0_.name as name3_3_0_, user0_.password as password4_3_0_ from users user0_ where user0_.id=? 
Hibernate: select taskedit0_.id as id1_0_0_, taskedit0_.task_id as task_id3_0_0_, taskedit0_.text as text2_0_0_ from task_edits taskedit0_ where taskedit0_.task_id=? 

請指教我的代碼有什麼問題,以及如何讓Hibernate的加載屬性延遲?謝謝!

+0

[這個答案](http://stackoverflow.com/a/36143746/4754790)提供的替代品時的概述它涉及到懶惰的一對一關聯,其中外鍵位於由子實體映射的表中。 –

回答

1

Hibernate無法代理自己的對象。 至少有三個這個問題衆所周知的解決方案: 最簡單的一個是僞造一對多的關係。這將起作用,因爲延遲加載收集比單一可空屬性的延遲加載容易得多,但通常如果使用複雜的JPQL/HQL查詢,此解決方案非常不方便。 另一個是使用構建時間字節碼的工具。有關更多詳細信息,請閱讀Hibernate文檔:19.1.7。使用lazy屬性獲取。請記住,在這種情況下,您必須將@LazyToOne(LazyToOneOption.NO_PROXY)註釋添加到一對一關係以使其變爲惰性。將提取設置爲LAZY是不夠的。 最後一個解決方案是使用運行時字節碼工具,但它只適用於那些在成熟的JEE環境中將Hibernate用作JPA提供程序的人(在這種情況下,將「hibernate.ejb.use_class_enhancer」設置爲true應該做到這一點:實體管理器配置),或者將Spring配置爲使用Hibernate進行運行時編織(這可能很難在一些較早的應用程序服務器上實現)。在這種情況下,@LazyToOne(LazyToOneOption.NO_PROXY)註釋也是必需的。

@Entity 
public class Animal implements FieldHandled { 
private Person owner; 
private FieldHandler fieldHandler; 

@OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal") 
@LazyToOne(LazyToOneOption.NO_PROXY) 
public Person getOwner() { 
    if (fieldHandler != null) { 
    return (Person) fieldHandler.readObject(this, "owner", owner); 
    } 
    return owner; 
} 

public void setOwner(Person owner) { 
    if (fieldHandler != null) { 
    this.owner = fieldHandler.writeObject(this, "owner", this.owner, owner); 
    return; 
    } 
    this.owner = owner; 
} 

public FieldHandler getFieldHandler() { 
    return fieldHandler; 
} 

public void setFieldHandler(FieldHandler fieldHandler) { 
    this.fieldHandler = fieldHandler; 
} 
} 

你可以試試這個: http://justonjava.blogspot.in/2010/09/lazy-one-to-one-and-one-to-many.html

參考: Why Lazy loading not working in one to one association?

+0

第一個問題是方法不是「開放」的,這就是爲什麼Hibernate無法創建代理。第二個問題是你所說的一對一映射。好的描述爲什麼它是這樣的:http://stackoverflow.com/questions/1444227/making-a-onetoone-relation-lazy – awfun

+0

請在你的答案中引用來源的重要部分。 –