2013-07-29 4 views
11

मैं सोच रहा हूं कि MyBatis 3 & स्प्रिंग 3 का उपयोग करके मेरे सम्मिलित बयान के साथ बैच ऑपरेशंस को कैसे कार्यान्वित किया जाए?माइबेटिस/स्प्रिंग के साथ बैच ऑपरेशंस को कैसे कार्यान्वित करें?

उदाहरण के लिए, यहाँ क्या वर्तमान में किया जा रहा है:

spring.xml:

<bean id="jndiTemplateDatasource" class="org.springframework.jndi.JndiTemplate"> 
    <property name="environment"> 
     <props> 
     <prop key="java.naming.factory.initial">${context.factory}</prop> 
     </props> 
    </property> 
</bean> 
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiTemplate" ref="jndiTemplateDatasource"/> 
    <property name="jndiName" value="${connectionpool.jndi}"/> 
</bean> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource"/> 
</bean> 

<tx:annotation-driven transaction-manager="transactionManager"/> 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
    <property name="configLocation" value="classpath:mybatis-config.xml"/> 
</bean> 
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
    <property name="basePackage" value="com.test" /> 
</bean> 

MyService.xml:

<insert id="insertMyRecord" parameterType="com.test.MyRecord" > 
    insert into ... // code removed 
</insert> 

MyService.java:

public interface MyService { 

    public void insertMyRecord (MyRecord); 
} 

MyControl ler.java:

@Controller 
public class MyController { 

    @Autowired 
    private MyService myService; 

    @Transactional 
    @RequestMapping(....) 
    public void bulkUpload (@RequestBody List<MyRecord> myRecords) { 
    for (MyRecord record : myRecords) { 
     myService.insertMyRecord(record); 
    } 
    } 
} 

अस्वीकरण: यही कारण है कि प्रदर्शन के उद्देश्य से सिर्फ छद्म कोड है

तो मैं चालू करने के लिए है कि एक बैच प्रक्रिया में क्या कर सकता है?

आदर्श रूप से मैं कोड में कम से कम "घुसपैठ" करने में सक्षम होना चाहता हूं, यानी एनोटेशन का अधिक पसंदीदा उपयोग करें, लेकिन यदि संभव नहीं है तो अगली सबसे अच्छी चीज़ क्या है?

इसके अलावा, इसे केवल एक ही सेवा के लिए कॉन्फ़िगर करने की आवश्यकता है, न कि परियोजना में सबकुछ के लिए।

+0

अधिक स्पष्ट होने के लिए, लक्ष्य एक प्रदर्शन के लिए रिकॉर्ड सम्मिलन में एक जेडीबीसी बैचिंग प्रकार के हैंडलिंग प्राप्त करना है, एक-एक-एक दृष्टिकोण के बजाय यह – Trant

उत्तर

9

यह उदाहरण चला रहा है और परीक्षण किया गया है ... बैच (ibatis + java)

का उपयोग कर एकाधिक पंक्तियों को अपडेट करें। मैं पार्टी से संबंधित तालिका से गिनती में भाग ले रहा हूं।

public static int updateBatch(List<MyModel> attendingUsrList) { 
    SqlSession session = ConnectionBuilderAction.getSqlSession(); 
    PartyDao partyDao = session.getMapper(PartyDao.class); 
    try { 
     if (attendingUsrList.size() > 0) { 
      partyDao.updateAttendingCountForParties(attendingUsrList); 
     } 
     session.commit(); 
    } catch (Throwable t) { 
     session.rollback(); 
     logger.error("Exception occurred during updateBatch : ", t); 
     throw new PersistenceException(t); 
    } finally { 
     session.close(); 
    } 
} 

मॉडल वर्ग जहां चर परिभाषित किया गया है:

public class MyModel { 

    private long attending_count; 
    private String eid; 

    public String getEid() { 
     return eid; 
    } 

    public void setEid(String eid) { 
     this.eid = eid; 
    } 

    public long getAttending_count() { 
     return attending_count; 
    } 

    public void setAttending_count(long attending_count) { 
     this.attending_count = attending_count; 
    } 


} 

party.xml कोड

वास्तविक क्वेरी जहां बैच निष्पादित

<foreach collection="attendingUsrList" item="model" separator=";"> 
    UPDATE parties SET attending_user_count = #{model.attending_count} 
    WHERE fb_party_id = #{model.eid} 
</foreach> 

इंटरफ़ेस यहाँ कोड

public interface PartyDao { 
    int updateAttendingCountForParties (@Param("attendingUsrList") List<FBEventModel>attendingUsrList); 
} 

यहाँ मेरी बैच सत्र कोड

public static synchronized SqlSession getSqlBatchSession() { 
    ConnectionBuilderAction connection = new ConnectionBuilderAction(); 
    sf = connection.getConnection(); 
    SqlSession session = sf.openSession(ExecutorType.BATCH); 
    return session; 
} 

SqlSession session = ConnectionBuilderAction.getSqlSession(); 
+1

यहां लापता जानकारी का मुख्य भाग यह है कि जब आप अपना एसक्यूएलशन खोलते हैं तो आपको एक्जिक्यूटोर टाइप टाइप करें। मानक MyBatis API में यह SQL वर्ग वर्ग के खोलने के लिए एक पैरामीटर है। यदि आप MyBatis-Spring का उपयोग कर रहे हैं तो आप इसे अपने SqlSessionTemplate के पैरामीटर के रूप में पास कर देंगे। यानी: <बीन आईडी = "sqlSession" वर्ग = "org.mybatis.spring.SqlSessionTemplate"> <कन्स्ट्रक्टर-एर्ग इंडेक्स = "0" रेफरी = "sqlSessionFactory" /> <कन्स्ट्रक्टर-एर्ग इंडेक्स = "1" मूल्य = "बैच" /> – jkratz

+0

नीचे आप 'getSqlBatchSession' को परिभाषित करते हैं, लेकिन आपके कोड में आप' getSqlSession' 'कहते हैं। क्या यह एक टाइपो है? – aioobe

+0

foreach का उपयोग नहीं करना चाहिए। अधिक कुशल तरीके से यहां देखें: http://stackoverflow.com/a/29264696/922348 – rimsky

1

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

एकल सेवा बनाने के लिए मैं सेवा इंटरफ़ेस generify करने की सिफारिश करेंगे:

public void bulkUpload (@RequestBody List<T> myRecords) 

तो फिर तुम वस्तु के प्रकार जांच कर सकते हैं और उचित नक्शाकार भंडार कहते हैं।

तो फिर तुम एक आम इंटरफेस बना कर अधिक यह generify कर सकते हैं:

public interface Creator<T> { 
    void create(T object); 
} 

और अपने नक्शाकार इंटरफ़ेस द्वारा यह विस्तार:

public interface MyService extends Creator<MyRecord>{} 

अब सबसे जटिल कदम: यदि आप एक की वस्तु मिल विशेष प्रकार, देखें कि सटीक मैपर इस वर्ग के लिए निर्माता इंटरफेस को लागू करता है (जावा प्रतिबिंब एपीआई का उपयोग करके) और विशेष विधि का आह्वान करता है।

package com.mydomain.repository; 

//imports ... 
import org.reflections.Reflections; 

@Repository(value = "dao") 
public class MyBatisDao { 

    private static final Reflections REFLECTIONS = new Reflections("com.mydomain"); 

    @Autowired 
    public SqlSessionManager sqlSessionManager; 

    public void create(Object o) { 
     Creator creator = getSpecialMapper(Creator.class, o); 
     creator.create(o); 
    } 

    // other CRUD methods 

    @SuppressWarnings("unchecked") 
    private <T> T getSpecialMapper(Class<T> specialClass, Object parameterObject) { 
     Class parameterClass = parameterObject.getClass(); 
     Class<T> mapperClass = getSubInterfaceParametrizedWith(specialClass, parameterClass); 
     return sqlSessionManager.getMapper(mapperClass); 
    } 

    private static <T, P> Class<? extends T> getSubInterfaceParametrizedWith(Class<T> superInterface, Class<P> parameterType) { 
     Set<Class<? extends T>> subInterfaces = REFLECTIONS.getSubTypesOf(superInterface); 
     for (Class<? extends T> subInterface: subInterfaces) { 
      for (Type genericInterface : subInterface.getGenericInterfaces()) { 
       if (!(genericInterface instanceof ParameterizedType)) continue; 
       ParameterizedType parameterizedType = (ParameterizedType) genericInterface; 
       Type rawType = parameterizedType.getRawType(); 
       if (rawType instanceof Class<?> && ((Class<?>) rawType).isAssignableFrom(superInterface)) { 
        for (Type type: parameterizedType.getActualTypeArguments()) { 
         if (type instanceof Class<?> && ((Class<?>) type).isAssignableFrom(parameterType)) { 
          return subInterface; 
         } 
        } 
       } 

      } 
     } 
     throw new IllegalStateException(String.format("No extension of %s found for parametrized type %s ", superInterface, parameterType)); 
    } 
} 

चेतावनी:

अब मैं आपको कोड मैं अपनी परियोजनाओं में से एक में उपयोग करने देने के! इस दृष्टिकोण से खराब प्रदर्शन प्रभाव हो सकता है इसलिए गैर-प्रदर्शन-महत्वपूर्ण कार्रवाइयों में इसका उपयोग करें

यदि आप थोक सम्मिलित करना चाहते हैं तो मैं here वर्णित थोक सम्मिलन के लिए mybatis foreach का उपयोग करने की अनुशंसा करता हूं।

यदि आपको लगता है कि आप हर प्रकार की वस्तुओं के लिए एसक्यूएल लिखना नहीं चाहते हैं तो आप बेहतर हाइबरनेट या किसी अन्य उन्नत ORM का उपयोग करते हैं। MyBatis सिर्फ एक एसक्यूएल मैपिंग इंटरफ़ेस है।

+0

बहुत अच्छी जानकारी है जिसका उपयोग मैं कर सकता हूं लेकिन यह बैचिंग को लागू करने की इच्छा को संबोधित नहीं करता है। मैं चाहता हूं कि प्रदर्शन के कारणों के लिए जेडीबीसी बैच के समान आवेषणों को संभालने के लिए मेरे लूप के लिए है, प्रत्येक डालने के बजाय एकल लेनदेन होने के बजाय – Trant

+0

@ टेंट तो इसका मतलब यह नहीं है कि आपको mybatis के साथ थोक सम्मिलन का उपयोग करने की आवश्यकता है foreach (ऊपर दिया गया लिंक)? – Nailgun

+0

लेकिन क्या MyBatis इसे एक अनुकूलित बैच ऑपरेशन में बदलता है या फिर भी यह एक-एक-एक सम्मिलित करता है? – Trant

8

है स्वीकार किए जाते हैं जवाब से ऊपर नहीं वास्तव में आप बैच मोड MyBatis के लिए मिलता है। आपको execorType.BATCH के माध्यम से उचित निष्पादक चुनने की आवश्यकता है। यह मानक MyBatis API में SqlSession.openSession के पैरामीटर के रूप में या SqlSessionTemplate के विकल्प के रूप में, MyBatis-Spring का उपयोग करते समय या तो पैरामीटर के रूप में पारित किया जाता है। यह किया जाता है:

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 
    <constructor-arg index="0" ref="sqlSessionFactory" /> 
    <constructor-arg index="1" value="BATCH" /> 
</bean> 

ऐसा कुछ भी नहीं है जिसे करने की आवश्यकता है।

+1

डॉननो वाई, इस एक्सएमएल कॉन्फ़िगरेशन के साथ, मेरा बैच सम्मिलन बहुत धीमा करता है, एक करके एक को घुमाने से कोई फर्क नहीं पड़ता। –

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