簡體   English   中英

甚至在事務中也可以休眠LazyInitializationException

[英]Hibernate LazyInitializationException even in transaction

我面臨與此非常相似的問題: 即使使用OpenSessionInViewFilter,另一個LazyInitializationException

我使用的是Hibernate 4.2.7.Final。 我有一個這樣映射的實體:

@Entity
@Table(...)
public class A {
    ...
    @OneToMany(fetch=FetchType.LAZY, mappedBy="b")
    private Set<B> bSet;
    ...
}

它加載大量數據,這就是為什么我需要在需要時加載它。 因此,我使用此contoller請求映射加載頁面:

@RequestMapping("/getDetails")
public ModelAndView showView(Model model) {
    ...
    for(B b : myService.getBSet()) {...}
    ...
}

服務正在交易中:

@Service
@Scope(value="session")
@Transactional("ora11transactionManager")
public class MyServiceImpl implements MyService {
    private A a;
    ...
    public Set<B> getBSet() {
        return a.getBSet();
    }
}

hibernate.cgf.xml中的事務管理器:

<bean id="ora11sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref bean="ora11source"/>
    </property>

    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">${debug}</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
            <prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
            <prop key="hibernate.cache.use_second_level_cache">true</prop>
        </props>
    </property>

    <property name="packagesToScan">
        <list>
            <value>mypackage</value>
        </list>
    </property>
</bean>
<bean id="ora11transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="ora11sessionFactory" />
</bean>

當我想加載getDetails視圖時,它將引發引用服務中該行的異常:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: <my-package>.A.bSet, could not initialize proxy - no Session

這不是我使用的唯一延遲獲取的集合,但在其他任何地方都可以使用。 延遲加載必須在事務中,並且在事務中(如您所見,我的服務實現)! 我什至在web.xml添加了org.springframework.orm.hibernate4.support.OpenSessionInViewFilter

我找不到任何解決方案,請告知!

更新(我實體的確切使用):

我有大量的As,每個A都有B。在一個視圖中,我可以顯示所有As,它們在列表中並顯示在數據表中。 每行的末尾都有一個按鈕,它調用並執行操作。 在此操作中,我保存了選定的A(在myService中,有一個用於選定A的設置器)。 此操作在controller1中。 當我想顯示A的B時,我將其設置為選中狀態並重定向到另一個視圖。 該視圖由另一個控制器管理,這就是為什么我將選定的A保存到服務(會話或單例作用域)的原因。

@Controller
@Scope("session")
public class Controller1 {
    ...
    public void setSelectedA(A selectedA) {
        myService.setSelectedA(selectedA);
    }
}

我什至試圖用這種方法達到B的集合,但不起作用(整個服務是事務性的,我試圖僅將事務性注釋設置為setselectedA()getBSet()方法,但沒有成功)。

您的服務是session作用域( @Scope(value="session") ),但是它不會自動使其成為線程安全的。 例如,如果您有一個cart對象(它是相同的servlet會話),則用戶可以刷新其頁面,並且該頁面將在服務器上從不同的線程進行處理,這將是另一個Hibernate會話,但具有相同的cart(和相同的Servlet會話) )。

問題在於,您在MySessionImpl中緩存的實體需要實時的Hibernate會話才能觸發B集的加載-第一個控制器完成處理后,該會話將關閉。

當從不同線程使用Hibernate會話時,也不能保證它們正常工作,因此您不能延長它們的壽命以在控制器B中提供延遲加載,因為它是在另一個線程中處理的。 因此,請避免在服務類中緩存分離的未初始化對象。 因此,當您調用return a.getBSet(); 您正在訪問會話到a附着不當前線程存在。

我將重構該代碼,以確保所有操作均在具有作用域singleton的線程安全服務中完成(該作用域在Spring中是默認的),並且其方法應該是粗粒度的-即創建一個在單個方法調用中盡可能多地執行的服務,並且方法被標注為@Transactional

如果您需要保留選定對象的列表(例如,Web商店購物車中的商品ID),則只需將其標識符(而非實體)存儲在會話范圍(按用戶)的Bean中,然后在需要時按ID加載它們在另一個控制器/線程中。 為了避免A實體進行額外的數據庫往返,您可以在Hibernate中啟用二級緩存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM