2017-03-03 8 views
6

के बिना लाया गया मेरी उम्मीद यह है कि जब एक लेनदेन के दायरे में संग्रह का उपयोग किया जाता है तो आलसी लोड संग्रह प्राप्त किया जाना चाहिए। उदाहरण के लिए, अगर मैं एक संग्रह प्राप्त करना चाहता हूं तो मैं foo.getBars.size() पर कॉल कर सकता हूं। एक सक्रिय लेन-देन के अभावस्प्रिंग डेटा जेपीए - आलसी लोड किए गए संग्रह को @ ट्रान्सएक्शनल

की तरह एक त्रुटि संदेश के साथ एक अपवाद में परिणाम चाहिए lazily सलाखों के एक संग्रह प्रारंभ करने में विफल: .... प्रॉक्सी प्रारंभ नहीं सकता है - कोई सत्र

हालांकि , मैंने देखा कि व्यवहार मेरे नवीनतम एप्लिकेशन में अलग है। मैं "डेटा-जेपीए" स्टार्टर के साथ स्प्रिंग बूट 1.5.1 का उपयोग कर रहा हूं। मैंने अतीत में स्प्रिंग बूट का उपयोग किया है, लेकिन डेटा-जेपीए स्टार्टर मेरे लिए नया है।

निम्नलिखित मामले पर विचार करें। मेरे पास आलसी भरा संग्रह बहुत आलसी है।

@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

स्प्रिंग बूट डिफ़ॉल्ट रूप से एक OpenEntityManagerInViewwInterceptor का उपयोग करने लगता है: https://github.com/spring-projects/spring-boot/blob/ मास्टर/वसंत-बूट-autoconfigure/src/मुख्य/जावा/org/springframework/बूट/autoconfigure/ORM/जेपीए/JpaBaseConfiguration.java # L203। यह भी देखें http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#common-plication-properties (और OpenEntityManagerInView के लिए खोजें) –

उत्तर

11

स्प्रिंग बूट डिफ़ॉल्ट रूप से एक OpenEntityManagerInView इंटरसेप्टर का उपयोग करता है। आप संपत्ति को spring.jpa.open-in-view को गलत पर सेट करके इसे बंद कर सकते हैं।

इस (और अन्य) जेपीए गुणों के संदर्भ के लिए 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() 
संबंधित मुद्दे