2013-04-23 8 views
23

मैं इस कोड के बराबर कैसे प्राप्त कर सकते हैं:स्प्रिंग डेटा जेपीए के साथ इकाइयों को देखते समय LockModeType.PESSIMISTIC_WRITE को कैसे सक्षम करें?

tx.begin(); 
Widget w = em.find(Widget.class, 1L, LockModeType.PESSIMISTIC_WRITE); 
w.decrementBy(4); 
em.flush(); 
tx.commit(); 

... लेकिन वसंत और वसंत-डाटा-जेपीए एनोटेशन का उपयोग?

अपने मौजूदा कोड का आधार है:

@Service 
@Transactional(readOnly = true) 
public class WidgetServiceImpl implements WidgetService 
{ 
    /** The spring-data widget repository which extends CrudRepository<Widget, Long>. */ 
    @Autowired 
    private WidgetRepository repo; 

    @Transactional(readOnly = false) 
    public void updateWidgetStock(Long id, int count) 
    { 
    Widget w = this.repo.findOne(id); 
    w.decrementBy(4); 
    this.repo.save(w); 
    } 
} 

लेकिन मैं निर्दिष्ट करने का तरीका है कि updateWidgetStock विधि में सब कुछ एक निराशावादी ताला सेट के साथ किया जाना चाहिए पता नहीं है।

एक स्प्रिंग डाटा जेपीए एनोटेशन org.springframework.data.jpa.repository.Lock जो आपको एक LockModeType सेट करने देता है, लेकिन अगर यह updateWidgetStock विधि पर डाल करने के लिए मान्य नहीं है मैं नहीं जानता। यह अधिक WidgetRepository पर टिप्पणी के जैसा लगता है, क्योंकि जावाडोक का कहना है:

org.springframework.data.jpa.repository
@Target (मूल्य = विधि)
@Retention (मूल्य = क्रम)
@Documented
सार्वजनिक @ इंटरफेस लॉक
एनोटेशन क्वेरी निष्पादित करते समय लॉकमोड टाइप टाइप करने के लिए उपयोग किया जाता है। किसी क्वेरी विधि पर क्वेरी का उपयोग करते समय या यदि आप विधि नाम से क्वेरी प्राप्त करते हैं तो इसका मूल्यांकन किया जाएगा।

... इसलिए यह सहायक नहीं लगता है।

मैं सेट के साथ अपना updateWidgetStock() विधि निष्पादित कैसे कर सकता हूं?

+0

इस सवाल का जवाब दोनों उपयोगी हो सकता है: http://stackoverflow.com/questions/11880924/how-to-add-custom-method -to-spring-data-jpa –

उत्तर

38

@Lock स्प्रिंग डेटा जेपीए के संस्करण 1.6 के रूप में सीआरयूडी विधियों पर समर्थित है (वास्तव में, पहले से ही milestone उपलब्ध है)। अधिक जानकारी के लिए यह ticket देखें।

कि संस्करण के साथ

आप बस की घोषणा के बाद:

interface WidgetRepository extends Repository<Widget, Long> { 

    @Lock(LockModeType.PESSIMISTIC_WRITE) 
    Widget findOne(Long id); 
} 

यह समर्थन भंडार प्रॉक्सी EntityManager पर find(…) कॉल करने के लिए कॉन्फ़िगर LockModeType लागू करने के लिए की CRUD कार्यान्वयन भाग का कारण होगा। हालांकि, अगर आप PostgreSQL का उपयोग कर रहे

/** 
* Repository for Wallet. 
*/ 
public interface WalletRepository extends CrudRepository<Wallet, Long>, JpaSpecificationExecutor<Wallet> { 

    @Lock(LockModeType.PESSIMISTIC_WRITE) 
    @Query("select w from Wallet w where w.id = :id") 
    Wallet findOneForUpdate(@Param("id") Long id); 
} 

, बातें कर सकते हैं:

+0

यह @ लॉक पहले से ही मेरे परीक्षण में वसंत-डेटा-जेपीए 1.4.1 के साथ काम करता है ... लेकिन फिर भी सवाल यह है कि, मैं कैसे पास कर सकता हूं लॉक टाइप? मैं हमेशा निराशावादी ताला का उपयोग नहीं करना चाहता, बहुत से सेनोरियो ज्यादातर पढ़ते हैं। लेकिन जब मुझे पता है कि मैं लिख रहा हूं, और यह विवाद होगा कि मैं निराशावादी ताला का उपयोग करना चाहता हूं। क्या मैं बना सकता हूं findOneLock (स्ट्रिंग, LockModeType)? –

+2

आह ठीक है, 1.4.1 में देख रहा है यह काम कर रहा है जब मैं इसे एक ओवरराइड खोज में जोड़ता हूं, लेकिन जब मैं इसे जोड़ता हूं तो यह मेरा खुद का खोज नहीं है BXXxx। मुख्य सवाल बनी हुई है, मैं कुछ समय में लॉक का उपयोग कैसे कर सकता हूं लेकिन हर समय नहीं। –

7

यदि आप इस उत्तर को अनदेखा करने के बजाय स्प्रिंग डेटा 1.6 या उससे अधिक का उपयोग करने में सक्षम हैं और ओलिवर के उत्तर का संदर्भ लें।

वसंत डेटा निराशावादी @Lock एनोटेशन केवल प्रश्नों के अनुसार लागू होते हैं (जैसा आपने बताया)। ऐसे एनोटेशन नहीं हैं जिन्हें मैं जानता हूं जो पूरे लेनदेन को प्रभावित कर सकते हैं। आप या तो findByOnePessimistic विधि बना सकते हैं जो एक निराशावादी ताला के साथ findByOne पर कॉल करता है या आप हमेशा निराशावादी ताला प्राप्त करने के लिए findByOne बदल सकते हैं।

यदि आप अपना स्वयं का समाधान लागू करना चाहते हैं तो शायद आप कर सकते हैं।

TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode); 

आप कुछ स्थिर ताला प्रबंधक जो एक ThreadLocal<LockMode> सदस्य चर था बना सकते हैं और फिर एक पहलू हर भंडार जो bindResource कहा जाता है में हर विधि के चारों ओर लिपटा है: हुड के अंतर्गत @Lock एनोटेशन जो निम्नलिखित करता LockModePopulatingMethodIntercceptor द्वारा संसाधित किया जाता है ThreadLocal में लॉक मोड सेट के साथ। यह आपको लॉक मोड को प्रति-थ्रेड आधार पर सेट करने की अनुमति देगा। फिर आप अपना खुद का @MethodLockMode एनोटेशन बना सकते हैं जो विधि को चलाने से पहले थ्रेड-विशिष्ट लॉक मोड सेट करता है और विधि को चलाने के बाद इसे साफ़ करता है।

+0

यदि कोई लेनदेन के अंत तक नहीं है (और इस प्रकार किसी भी निम्न अद्यतन को शामिल करता है) तो क्वेरी पर निराशावादी ताला रखने का क्या मतलब है? –

+0

एक प्रश्न में प्राप्त एक निराशावादी ताला लेनदेन के अंत तक पकड़ना चाहिए। उन दूसरे दो पैराग्राफ वर्णन कर रहे थे कि आप एक लेनदेन कैसे बना सकते हैं जहां सभी प्रश्नों ने निराशावादी ताले प्राप्त किए। – Pace

+2

यदि मैं सही ढंग से समझता हूं, तो मैं केवल उस निष्कर्ष को प्राप्त कर सकता हूं जिसे मैं 'ढूंढने' को निराशावादी ताला का उपयोग करके प्राप्त करना चाहता हूं - वह लॉक मेरे लेनदेन के अंत तक होना चाहिए (जो मेरे 'अपडेट WidgetStock()' विधि के अंत में समाप्त होगा क्या यह सही है? –

5

आप मानक findOne() विधि ओवरराइड करने के लिए नहीं करना चाहते हैं, आप अपने कस्टम विधि में एक ताला सिर्फ इस तरह select ... for update क्वेरी का उपयोग करके प्राप्त कर सकते हैं जब आप डेडलॉक्स से बचने के लिए लॉक टाइमआउट सेट करना चाहते हैं तो थोड़ा जटिल हो जाएं। PostgreSQL मानक गुण javax.persistence.lock.timeout जेपीए गुणों में सेट किया गया है या @QueryHint एनोटेशन में अनदेखा करता है।

एकमात्र तरीका मैं इसे काम कर सकता था एक कस्टम भंडार बनाना और इकाई को लॉक करने से पहले मैन्युअल रूप से टाइमआउट सेट करना था। यह अच्छा नहीं है, लेकिन कम से कम यह काम कर रहा है:

public class WalletRepositoryImpl implements WalletRepositoryCustom { 

@PersistenceContext 
private EntityManager em; 


@Override 
public Wallet findOneForUpdate(Long id) { 
    // explicitly set lock timeout (necessary in PostgreSQL) 
    em.createNativeQuery("set local lock_timeout to '2s';").executeUpdate(); 

    Wallet wallet = em.find(Wallet.class, id); 

    if (wallet != null) { 
     em.lock(wallet, LockModeType.PESSIMISTIC_WRITE); 
    } 

    return wallet; 
} 

}

+0

दुर्भाग्यवश, यह 'entityManager' कैश को रीफ्रेश नहीं करता है। आपको मैन्युअल रूप से 'entityManager.refresh (वॉलेट)' करना होगा – rcomblen

संबंधित मुद्दे