[SPRING] MyBatis / Spring을 사용하여 배치 작업을 구현하는 방법은 무엇입니까?
SPRINGMyBatis / Spring을 사용하여 배치 작업을 구현하는 방법은 무엇입니까?
내 삽입 문을 MyBatis 3 & Spring 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);
}
MyController.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);
}
}
}
면책 조항 : 이는 데모 목적을위한 단지 의사 코드입니다.
그렇다면이를 배치 프로세스로 바꾸려면 어떻게해야합니까?
이상적으로는 코드에 "침입"을 최소화하거나 주석을 사용하는 것이 더 좋을 수 있기를 원하지만 가능하지 않은 경우 가장 좋은 것은 무엇입니까?
또한 프로젝트의 모든 항목이 아니라이 서비스에 대해서만 구성해야합니다.
해결법
-
==============================
1.이것은 실행 및 테스트 예제입니다 ... 일괄 처리를 사용하여 여러 행 업데이트 (ibatis + java)
이것은 실행 및 테스트 예제입니다 ... 일괄 처리를 사용하여 여러 행 업데이트 (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();
-
==============================
2.위의 대답은 실제로 MyBatis에 대한 일괄 처리 모드를 제공하지 않습니다. ExecutorType.BATCH를 통해 적절한 Executor를 선택해야합니다. 이는 표준 MyBatis API의 SqlSession.openSession에 대한 매개 변수로 전달되거나 MyBatis-Spring을 사용하는 경우 SqlSessionTemplate에 대한 옵션으로 전달됩니다. 그건을 통해 이루어집니다 :
위의 대답은 실제로 MyBatis에 대한 일괄 처리 모드를 제공하지 않습니다. ExecutorType.BATCH를 통해 적절한 Executor를 선택해야합니다. 이는 표준 MyBatis API의 SqlSession.openSession에 대한 매개 변수로 전달되거나 MyBatis-Spring을 사용하는 경우 SqlSessionTemplate에 대한 옵션으로 전달됩니다. 그건을 통해 이루어집니다 :
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory" /> <constructor-arg index="1" value="BATCH" /> </bean>
끝내야 할 다른 것은 없습니다.
-
==============================
3.나는이 질문을 완전히 이해하고 있는지 확신 할 수 없지만, 나는 당신에게 내 생각을 전달하려고 노력할 것이다.
나는이 질문을 완전히 이해하고 있는지 확신 할 수 없지만, 나는 당신에게 내 생각을 전달하려고 노력할 것이다.
단일 서비스를 만들기 위해 서비스 인터페이스를 생성하는 것이 좋습니다.
public void bulkUpload (@RequestBody List<T> myRecords)
그런 다음 객체의 유형을 확인하고 Propper Mapper 저장소를 호출 할 수 있습니다.
그런 다음 공통 인터페이스를 만들어 더 많이 생성 할 수 있습니다.
public interface Creator<T> { void create(T object); }
매퍼 인터페이스로 확장 할 수 있습니다.
public interface MyService extends Creator<MyRecord>{}
이제 가장 복잡한 단계 : 특정 유형의 객체를 가져 와서 정확한 매퍼가 (Java 리플렉션 API를 사용하여)이 클래스의 작성자 인터페이스를 구현하고 특정 메소드를 호출하는지 확인하십시오.
이제는 내 프로젝트 중 하나에서 사용하는 코드를 제공합니다.
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)); } }
경고! 이 접근 방식은 성능에 좋지 않은 영향을 미칠 수 있으므로 성능에 중요하지 않은 작업
대량 삽입을 원한다면 여기에 설명 된대로 대량 삽입을 위해 mybatis foreach를 사용하는 것이 좋습니다.
모든 유형의 객체에 대해 sql을 작성하지 않으려면 Hibernate 나 다른 고급 ORM을 사용하는 것이 좋습니다. MyBatis는 SQL 매핑 인터페이스 일뿐입니다.
from https://stackoverflow.com/questions/17928799/how-to-implement-batch-operations-with-mybatis-spring by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 봄 부팅 응용 프로그램에서 봄 보안 해제 (0) | 2018.12.25 |
---|---|
[SPRING] Spring 'HandlerMethodArgumentResolver'에서 요청 본문을 여러 번 읽으려면 어떻게해야합니까? (0) | 2018.12.25 |
[SPRING] 구성 클래스에 대한 가져 오기 후보를 처리하지 못했습니다. (0) | 2018.12.25 |
[SPRING] 스프링 배치에서 멀티 스레딩을 설정하는 방법은 무엇입니까? (0) | 2018.12.25 |
[SPRING] Spring MVC 요청 메소드 'GET'이 지원되지 않는 이유는 무엇입니까? (0) | 2018.12.25 |