2017-03-03 76 views
6

我的期望是,當在事務範圍內訪問集合時,應該獲取延遲加載的集合。例如,如果我想獲取集合,我可以撥打foo.getBars.size()。由於沒有活動事務的應該導致一個錯誤消息的異常像Spring Data JPA - 無需@Transactional獲取Lazy Loaded集合

未能懶洋洋地初始化酒吧集合:......無法 初始化代理 - 沒有會話

然而,我注意到我的最新應用程序中的行爲不同。我正在使用Spring Boot 1.5.1和「data-jpa」啓動器。過去我使用過Spring Boot,但data-jpa starter對我來說是新的。

請考慮以下情況。我有一個懶加載的ManyToMany集合。

@SuppressWarnings("serial") 
@Entity 
@Table(name = "foo") 
public class Foo implements java.io.Serializable { 
    .... 
    private Set<Bar> bars = new HashSet<Bar>(0); 
    .... 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    @JoinTable(name = "foo_bar_map", 
     joinColumns = {@JoinColumn(name = "foo_id", nullable = false, updatable = false)}, 
     inverseJoinColumns = {@JoinColumn(name = "bar_id", nullable = false, updatable = false)}) 
    public Set<Bar> getBars() { 
     return this.bars; 
    } 

    public void setBar(Set<Bar> bars) { 
     this.bars = bars; 
    } 

我的服務方法沒有被標記爲事務性,但我訪問延遲加載的集合

@Service 
public class FooServiceImpl implements FooService { 

    @Autowired 
    private FooRepository fooRepo; 


    @Override 
    public FooDTO findById(int fooId) { 
     Foo foo = fooRepo.findOne(fooId); 
     // The FooDTO constructor will access foo.getBars() 
     return new FooDTO(foo); 
    } 

而對於在FooDTO構造

public FooDTO(Foo foo) { 
    ... 
    for (Bar bar : foo.getBars()) { 
     this.bars.add(bar); 
    } 
} 

出乎我的意料和過去的情況下經驗,此代碼成功執行並獲取集合。此外,如果我在服務方法中引發斷點,則可以遍歷代碼並查看日誌中的SQL語句,這些語句用於在調用fooRepo之後獲取條形圖。在我致電fooRepo之後,我預計交易將被關閉。

這裏發生了什麼?

+0

誰致電該服務?我的猜測是調用者是事務性的。 –

+0

@JBNizet這個方法被一個控制器調用,它沒有標記爲事務性的...... –

+1

默認情況下,Spring引導似乎使用OpenEntityManagerInViewwInterceptor:https://github.com/spring-projects/spring-boot/blob/主/彈簧引導自動配置/ SRC /主/ JAVA /組織/ springframework的/引導/自動配置/ ORM/JPA/JpaBaseConfiguration.java#L203。另請參閱http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#common-application-properties(並搜索OpenEntityManagerInView) –

回答

11

Spring Boot默認使用OpenEntityManagerInView攔截器。您可以通過將屬性spring.jpa.open-in-view設置爲false來關閉它。

有關此(及其他)JPA屬性的參考信息,請參見the documentation

+0

如此之外,findById,應該不再工作? –

1

您可以打開日誌記錄來檢查是否正在打開一個事務。

org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction 

org.hibernate.engine.transaction.internal.jta.JtaTransaction 

此外,您可以設置一個斷點並使用這個靜態方法來檢查,如果交易是開放的。

org.springframework.transaction.support.TransactionSynchronizationManager.isActualTransactionActive()