2012-10-16 25 views
7

हम एक स्प्रिंग 3.1/हाइबरनेट 4/जावा 7/टॉमकैट 7/एमएसएसक्यूएल 2008 आर 2 वेब एप्लिकेशन चलाते हैं। हमें विरासत डेटा और संग्रहीत डेटा से निपटना होगा। किसी संग्रह से डेटा निकालने पर, हमें मूल अद्वितीय पहचानकर्ता का उपयोग करने की आवश्यकता होती है ताकि अन्य (गैर-संग्रहित) रिकॉर्ड सही ढंग से फिर से हाइड्रेट हो जाएंगे। ये पहचानकर्ता प्राथमिक कुंजी/ऑटो वृद्धि क्षेत्र में संग्रहीत हैं।हाइबरनेट 3.5 बनाम 4 IDENTITY_INSERT मुद्दे

पहले अब, जब हम वसंत 3.0 उपयोग कर रहे थे/हाइबरनेट करने के लिए 3.5, निम्न कोड एक निकाले रिकॉर्ड अपने उचित तालिका में वापस INSERT के लिए काम किया (हम पहले से ही चर session, entity, और fullTableName दायरे में है):

session.doWork(new Work() 
{ 
    @Override 
    public void execute(Connection connection) throws SQLException 
    { 
     PreparedStatement statement = null; 
     try 
     { 
      statement = connection.prepareStatement(String.format("SET IDENTITY_INSERT %s ON", fullTableName)); 
      statement.execute(); 

      session.save(entity); 

      statement = connection.prepareStatement(String.format("SET IDENTITY_INSERT %s OFF", fullTableName)); 
      statement.execute(); 
     } 
     finally 
     { /* close the statement */ } 
    } 
}); 

जैसे कि मैंने उल्लेख किया है, यह सब हाइबरनेट 3.5 में ठीक काम किया, लेकिन अब है कि हम हाइबरनेट करने के लिए 4 अपग्रेड किया है, यह काम करना बंद कर चुका है। क्या कार्य और पृथक कार्य के बीच अंतर के साथ कुछ है?

session.createSQLQuery(String.format("SET IDENTITY_INSERT %s ON", fullTableName)).executeUpdate(); 
session.save(entity); 
session.createSQLQuery(String.format("SET IDENTITY_INSERT %s OFF", fullTableName)).executeUpdate(); 

बहरहाल, यह या तो काम नहीं किया:

समस्या का समाधान, और किसी भी कार्य इंटरफ़ेस मुद्दों से बचने के प्रयास में, हम निम्नलिखित की कोशिश की। विशेष रूप से, जो अपवाद फेंक दिया जाता है वह java.sql.SQLException: Cannot insert explicit value for identity column in table 'Employee' when IDENTITY_INSERT is set to OFF. है, फिर भी यह स्पष्ट होना चाहिए कि हम इसे चालू करने के लिए दर्द से गुजर रहे हैं।

हमने स्थिति का एक SQL सर्वर प्रोफाइलर ट्रेस किया, और कुछ दिलचस्प पाया। कुछ हमारे लेनदेन निकायों में IMPLICIT_TRANSACTIONS चालू कर रहा है।

SET IMPLICIT_TRANSACTIONS ON 
go 
declare @p1 int 
set @p1=55 
exec sp_prepare @p1 output,N'',N'SET IDENTITY_INSERT <schema>.Employee ON',1 
select @p1 
go 
exec sp_execute 55 
go 

declare @p1 int 
set @p1=56 
exec sp_prepare @p1 output,N'<parameters for the INSERT>',N'insert into <schema>.Employee (<all the column names>) values (<all the parameters>)',1 
select @p1 
go 
exec sp_execute 56,<the actual values to insert> 
go 
IF @@TRANCOUNT > 0 ROLLBACK TRAN 
go 
IF @@TRANCOUNT > 0 COMMIT TRAN 
SET IMPLICIT_TRANSACTIONS OFF 
go 
exec sp_execute 54,N'Error writing EMPLOYEE archive record. ',<an id>,N'1' 
go 

, हम विशेष रूप से IMPLICIT_TRANSACTIONS सेट कर रहे हैं बंद हो सकता है, अब कनेक्शन के माध्यम से: यहाँ प्रोफाइलर का पता लगाने से कुछ नमूना उत्पादन (मैं बदल दिया है छोटे लेबल के साथ डेटा के कुछ बड़े बिट्स <schema> साथ हमारी वास्तविक स्कीमा, और) है हमारे लेनदेन में .setAutoCommit (झूठा) (लेनदेन स्प्रिंग @ ट्रान्सैक्शनल और हाइबरनेट लेनदेन प्रबंधक के माध्यम से प्रबंधित किया जा रहा है)। जाहिर है, यह काम नहीं कर रहा है, लेकिन setAutoCommit का उपयोग करने के अलावा विकल्प क्या हैं, और यह Spring3.0/Hibernate 3.5 में क्यों काम करेगा लेकिन वसंत 3.1/हाइबरनेट 4 नहीं?

किसी भी विचार या सुझाव के लिए धन्यवाद - हम स्टंप हो गए हैं।

उत्तर

2

खैर, यह एक सूक्ष्म समाधान था ...

हमारे कार्य कॉल आंतरिक रूप से एक java.sql.PreparedStatement इस्तेमाल किया है, और हम तो execute() विधि कहा जाता है। जाहिर है, यह SQL सर्वर को अपने स्वयं के संग्रहीत प्रक्रिया में कमांड को लपेटने के लिए कहता है, क्योंकि कुछ कोड नमूने दिखाते हैं।

हम एक PreparedStatement को बस एक java.sql.Statement का उपयोग कर और उसके execute() विधि कॉल करने से बदल दिया है:

session.doWork(new Work() 
{ 
    @Override 
    public void execute(Connection connection) throws SQLException 
    { 
     Statement statement = null; 
     try 
     { 
      statement = connection.createStatement(); 
      statement.execute(String.format("SET IDENTITY_INSERT %s ON", fullTableName)); 

      session.save(entity); 

      statement = connection.createStatement(); 
      statement.execute(String.format("SET IDENTITY_INSERT %s OFF", fullTableName)); 
     } 
     finally 
     { /* close the statement */ } 
    } 
}); 

तो, क्या अंतर है? जहां तक ​​हम कह सकते हैं, PreparedStatement प्री-संकलित एसक्यूएल उत्पन्न करता है, जबकि Statement स्थैतिक एसक्यूएल उत्पन्न करता है ... वास्तव में हमें IDENTITY_INSERT पर कॉल के लिए क्या चाहिए!

सबक: घोटाले और खलनायक के कई छिद्र हैं ... हमें सावधान रहना चाहिए!

+0

आपको बहुत धन्यवाद, निश्चित रूप से, यह मुझे बहुत समय बचाता है। –

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

  • कोई संबंधित समस्या नहीं^_^