@Transactional
वसंत में एनोटेशन आपके ऑब्जेक्ट को प्रॉक्सी में लपेटकर काम करता है जो बदले में @Transactional
के साथ एनोटेट किए गए तरीकों को लपेटता है एक लेन-देन में। क्योंकि यह एनोटेशन निजी तरीकों पर काम नहीं करेगा (जैसा कि आपके उदाहरण में है) क्योंकि निजी तरीके इनहेरिट नहीं किए जा सकते हैं => उन्हें लपेटा नहीं जा सकता (यह सच नहीं है यदि आप पहलू के साथ घोषणात्मक लेनदेन का उपयोग करते हैं, तो नीचे प्रॉक्सी से संबंधित चेतावनी लागू नहीं होती हैं)।
कैसे @Transactional
. की बुनियादी व्याख्या यहां दी गई है वसंत जादू काम करता है।
आपने लिखा:
class A {
@Transactional
public void method() {
}
}
लेकिन जब आप बीन इंजेक्ट करते हैं तो आपको वास्तव में यही मिलता है:
class ProxiedA extends A {
private final A a;
public ProxiedA(A a) {
this.a = a;
}
@Override
public void method() {
try {
// open transaction ...
a.method();
// commit transaction
} catch (RuntimeException e) {
// rollback transaction
} catch (Exception e) {
// commit transaction
}
}
}
इसकी सीमाएँ हैं। वे @PostConstruct
. के साथ काम नहीं करते हैं विधियाँ क्योंकि उन्हें वस्तु के समीप होने से पहले बुलाया जाता है। और भले ही आपने सभी सही तरीके से कॉन्फ़िगर किया हो, लेन-देन केवल अनचेक . पर ही वापस रोल किए जाते हैं डिफ़ॉल्ट रूप से अपवाद। @Transactional(rollbackFor={CustomCheckedException.class})
. का उपयोग करें अगर आपको कुछ चेक किए गए अपवाद पर रोलबैक की आवश्यकता है।
एक और बार-बार सामने आने वाली चेतावनी मुझे पता है:
@Transactional
विधि केवल तभी काम करेगी जब आप इसे "बाहर से" कहते हैं, निम्नलिखित उदाहरण में b()
लेन-देन में लपेटा नहीं जाएगा:
class X {
public void a() {
b();
}
@Transactional
public void b() {
}
}
ऐसा इसलिए भी है क्योंकि @Transactional
आपकी वस्तु को प्रॉक्सी करके काम करता है। ऊपर के उदाहरण में a()
कॉल करेंगे X.b()
उन्नत "स्प्रिंग प्रॉक्सी" विधि नहीं b()
इसलिए कोई लेन-देन नहीं होगा। वर्कअराउंड के रूप में आपको b()
. पर कॉल करना होगा दूसरे सेम से।
जब आप इनमें से किसी भी चेतावनी का सामना करते हैं और सुझाए गए समाधान का उपयोग नहीं कर सकते हैं (विधि को गैर-निजी बनाएं या b()
पर कॉल करें। दूसरे बीन से) आप TransactionTemplate
का उपयोग कर सकते हैं घोषणात्मक लेनदेन के बजाय:
public class A {
@Autowired
TransactionTemplate transactionTemplate;
public void method() {
transactionTemplate.execute(status -> {
A();
B();
return null;
});
}
...
}
अपडेट करें
उपरोक्त जानकारी का उपयोग करके ओपी अद्यतन प्रश्न का उत्तर देना।
<ब्लॉकक्वॉट>@Transactional के साथ किस विधि को एनोटेट किया जाना चाहिए:परिवर्तन ()? डेटाबेस चेंज ()?
@Transactional(rollbackFor={Exception.class})
public void changes() throws Exception {
someLogicBefore();
databaseChanges();
someLogicAfter();
}
सुनिश्चित करें कि changes()
एक बीन के "बाहर से" कहा जाता है, कक्षा से ही नहीं और संदर्भ के बाद तत्काल किया गया था (उदाहरण के लिए यह afterPropertiesSet()
नहीं है या @PostConstruct
एनोटेट विधि)। समझें कि स्प्रिंग रोलबैक लेनदेन केवल डिफ़ॉल्ट रूप से अनियंत्रित अपवादों के लिए होता है (रोलबैक में अधिक विशिष्ट होने का प्रयास करेंचेक अपवाद सूची के लिए)।