कल्पना करें कि आप एक ई-कॉमर्स प्रणाली पर काम कर रहे हैं और हजारों लोग एक ही समय में अंतिम शेष उत्पाद खरीदने का प्रयास करते हैं। हालाँकि, उनमें से कई चेकआउट के लिए आगे बढ़ सकते हैं और ऑर्डर पूरा कर सकते हैं। जब आप अपने स्टॉक की जांच करते हैं, तो आपके पास नकारात्मक मात्रा वाला एक उत्पाद होता है। यह कैसे संभव हुआ, और आप इसे कैसे हल कर सकते हैं?
आइए कोड करें! पहली चीज़ जो आप सोच सकते हैं वह है चेकआउट से पहले स्टॉक की जाँच करना। शायद कुछ इस तरह:
public void validateAndDecreaseSolution(long productId, int quantity { OptionalstockByProductId = stockRepository.findStockByProductId(productId); int stock = stockByProductId.orElseThrow().getStock(); int possibleStock = stock - quantity; if (stock आप इस सत्यापन का उपयोग कर सकते हैं, लेकिन जब हम प्रति सेकंड सैकड़ों, हजारों, लाखों या यहां तक कि दर्जनों अनुरोधों के बारे में बात करते हैं, तो यह सत्यापन पर्याप्त नहीं होगा। जब 10 अनुरोध एक ही समय में कोड के इस टुकड़े तक पहुंचते हैं और डेटाबेस StockByProductId के लिए समान मान लौटाता है, तो आपका कोड टूट जाएगा। जब हम यह सत्यापन करते हैं तो आपको अन्य अनुरोधों को अवरुद्ध करने का एक तरीका चाहिए।
पहला समाधान - अद्यतन के लिए
अपने चयन पर एक लॉक स्टेटमेंट जोड़ें। इस उदाहरण में मैंने स्प्रिंग डेटा के साथ FOR UPDATE का उपयोग करके ऐसा किया। जैसा कि PostgreSQL दस्तावेज़ कहता है
FOR UPDATE के कारण SELECT स्टेटमेंट द्वारा पुनर्प्राप्त पंक्तियाँ लॉक हो जाती हैं जैसे कि अपडेट के लिए। यह उन्हें वर्तमान लेनदेन समाप्त होने तक अन्य लेनदेन द्वारा संशोधित या हटाए जाने से रोकता है।
@Query(value = "SELECT * FROM stocks s WHERE s.product_id = ?1 FOR UPDATE", nativeQuery = true) OptionalfindStockByProductIdWithLock(Long productId); public void validateAndDecreaseSolution1(long productId, int quantity) { OptionalstockByProductId = stockRepository.findStockByProductIdWithLock(productId); // ... validate stockRepository.decreaseStock(productId, quantity); } उत्पाद आईडी का उपयोग करके स्टॉक तालिका के सभी अनुरोध वास्तविक लेनदेन समाप्त होने तक प्रतीक्षा करेंगे। यहां उद्देश्य यह सुनिश्चित करना है कि आपको स्टॉक का अंतिम अद्यतन मूल्य प्राप्त हो।
दूसरा समाधान - pg_advisory_xact_lock
यह समाधान पिछले समाधान के समान है, लेकिन आप चुन सकते हैं कि ताले की कुंजी क्या है। जब तक हम सत्यापन और स्टॉक में कमी की सभी प्रक्रिया पूरी नहीं कर लेते, हम पूरे लेन-देन को लॉक कर देंगे।
public void acquireLockAndDecreaseSolution2(long productId, int quantity) { Query nativeQuery = entityManager.createNativeQuery("select pg_advisory_xact_lock(:lockId)"); nativeQuery.setParameter("lockId", productId); nativeQuery.getSingleResult(); OptionalstockByProductId = stockRepository.findStockByProductId(productId); // check stock and throws exception if it is necessary stockRepository.decreaseStock(productId, quantity); } अगला अनुरोध इस लेनदेन के समाप्त होने के बाद केवल उसी आईडी वाले उत्पाद के साथ इंटरैक्ट करेगा।
तीसरा समाधान - कहां खंड
इस मामले में, हम अपनी पंक्ति या लेनदेन को लॉक नहीं करेंगे। आइए इस लेन-देन को अद्यतन विवरण तक जारी रखने की अनुमति दें। अंतिम शर्त पर ध्यान दें: स्टॉक> 0. यह हमारे स्टॉक को शून्य से कम नहीं होने देगा। इसलिए यदि दो लोग एक ही समय में खरीदने का प्रयास करते हैं, तो उनमें से एक को एक त्रुटि प्राप्त होगी क्योंकि हमारा डेटाबेस स्टॉक
@Transactional @Modifying @Query(nativeQuery = true, value = "UPDATE stocks SET stock = stock - :quantity WHERE product_id = :productId AND stock > 0") int decreaseStockWhereQuantityGreaterThanZero(@Param("productId") Long productId, @Param("quantity") int quantity);निष्कर्ष
पहले और दूसरे समाधान एक रणनीति के रूप में निराशावादी लॉकिंग का उपयोग करते हैं। तीसरा है आशावादी लॉकिंग. निराशावादी लॉकिंग रणनीति का उपयोग तब किया जाता है जब आप इस संसाधन से जुड़े किसी भी कार्य को करते समय किसी संसाधन तक प्रतिबंधात्मक पहुंच चाहते हैं। जब तक आप अपनी प्रक्रिया पूरी नहीं कर लेते, लक्ष्य संसाधन किसी भी अन्य पहुंच के लिए लॉक रहेगा। गतिरोधों से सावधान रहें!
आशावादी लॉकिंग के साथ, आप बिना किसी रुकावट के एक ही संसाधन पर विभिन्न क्वेरी कर सकते हैं। इसका उपयोग तब किया जाता है जब संघर्ष होने की संभावना नहीं होती है। आमतौर पर, आपके पास अपनी पंक्ति से संबंधित एक संस्करण होगा, और जब आप इस पंक्ति को अपडेट करते हैं, तो डेटाबेस आपके पंक्ति संस्करण की तुलना डेटाबेस में पंक्ति संस्करण से करेगा। यदि दोनों समान हों तो परिवर्तन सफल होगा। यदि नहीं, तो आपको पुनः प्रयास करना होगा. जैसा कि आप देख सकते हैं, मैं इस आलेख में किसी भी संस्करण पंक्ति का उपयोग नहीं करता हूं, लेकिन मेरा तीसरा समाधान किसी भी अनुरोध को अवरुद्ध नहीं करता है और स्टॉक> 0 स्थिति का उपयोग करके संगामिति को नियंत्रित करता है।
यदि आप पूरा कोड देखना चाहते हैं, तो आप मेरे GitHub पर देख सकते हैं।
निराशावादी और आशावादी लॉकिंग को लागू करने के लिए कई अन्य रणनीतियां हैं, उदाहरण के लिए आप स्किप लॉक्ड के साथ अपडेट के बारे में अधिक खोज सकते हैं।
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3