개발환경 :
  - SpringFramework 3.1.1. Release
  - JDK1.8

순수 java code에서 사용할 땐 ThreadPoolExecutor을 사용했으나, 현재 프로젝트는 Spring을 사용하고 있기에 Spring에서 관리가 가능한 ThreadPoolTaskExecutor을 적용하며 OOM이 나지 않기 위해 각 스레드에서 mybatis의 resultHandler를 사용하기로 함

해당 기능 적용 목적 : 문자 발송이 승인된 건은 문자 발송할 양에 따라 쓰레드 개수를 나눠서 분할 처리
(단일 스레드 처리 시 약 13만건 발송 시 22시간 소요) => 분할처리 적용 후 약 13만 건 발송 시 4시간 30분 소요 대략 80%정도의 시간 감소 효과 발생

1. applicationContext.xml 설정
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  <property name="corePoolSize" value="지정 스레드수"/>
  <property name="queueCapacity" value="태스크 대기 수"/>
  (이외에도 maxPoolSize 등 다른 설정할 것이 있으니 따로 확인)
</bean>

2. java Service.java 
@Autowired
private ThreadPoolTaskExecutor taskExecutor; 

(개인 프로젝트가 아니라 필요한 부분만 발췌하여 간략히 작성)
public void sendSMS() {
~~~ 처리할 양에 따른 적용할 스레드 수 계산로직 ~~~
taskExecutor.setCorePoolSize(스레드 수);
for(~~~~) {
  taskExecutor.submit(new SMSThread(필요한 파라미터 변수));
}
}

3. SMSThread.java
Runnable 인터페이스 구현
public void run() {
  mapper.selectSMSHandler(~~, new ResultHandler() {
   @Override
   public void handleResult(ResultContext context) {
     try {
        SMSdto rowData = (SMSdto) context.getResultObject();
        ~~~ row별로 읽은 데이터 처리 로직 ~~~
     } catch () {}
   }
});

 

[발생했던 문제]

1. ResultHandler를 사용했으나 오류 로그도 안 남고(? 정확하게 기억이 안남 ㅠㅠ) 읽은 row에 대해 처리 로직 수행이 안되는 경우
  => ResultHandler 안에서 try catch 구문을 사용하여 오류 확인. 기존에 테스트를 하며 현재 사용 안하는 변수가 있었는데 해당 변수에서 값을 참조하여 log찍는 곳에서 오류 발생하여 해당 변수 삭제.

2. 1건에 대한 처리는 완벽하게 수행되나 2건 째부터는 TaskRejectedExeption 발생
  => 태스크 대기 큐 설정을 안해서 그런 줄 알고 remainingCapacity()를 찍어보았으나 해당 없음.(0은 대기 큐 미사용이었으나 나의 경우 2로 출력)
       shutdown 메소드를 사용한 경우 추가적인 태스크를 받을 수 없다는 걸 확인. isShutDown()메소드로 확인 해봤더니 true로 출력....? 코드를 봤더니 기존 java 프로젝에서 테스트 하던 코드를 그대로 들고왔던 곳에서 shutdown 코드가 남아있는 것을 발견. 해당 코드 삭제 후 대기 큐에 정상적으로 들어와서 처리 완료된 것 확인

Posted by 知彼知己百戰不殆
,

개발 환경 : 
  -SpringFramework 3.1.1. Release

1. applicationContext.xml 파일 설정(굵은/붉은 글씨들은 각자의 상황에 맞게 변경 가능한 변수명 개념)

<bean id ="dataSource1" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
  <property name="driverClass" vlaue="oracle.jdbc.OracleDriver"/>
  < property name="url" vlaue="jdbc:oracle:thin:@IP:PORT:SID"/>
  <property name="username" vlaue="아이디"/>
  <property name="password" vlaue="비밀번호"/>
</bean>

<bean id="dataSource2" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
  <property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
  <property name="url" value="jdbc:sqlserver://IP:PORT;databaseName=데이터베이스명;trustServerCertificate=true"/>
  <property name="username" value="아이디"/>
  <property name="password" value="비밀번호"/>  
</bean>
 

<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource1"/>
  <property name="mapperLocations" value="classpath*:매퍼가 들어가 있는 패키지명/*.xml"/>
</bean>
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource2"/>
  <property name="mapperLocations" value="classpath*:2번째DB를 연결할 매퍼가 들어가 있는 패키지명/*.xml"/>
</bean>

<bean id="sqlSessionTemplate1" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg ref="sqlSessionFactory1"></constructor-arg>
</bean>
<bean id="sqlSessionTemplate2" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg ref="sqlSessionFactory2"></constructor-arg>
</bean>

<bean id="1MapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="1번 database연결할 패키지위치"/>
  <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate1"/>
</bean>
<bean id="2MapperScannerConfigurer" class="~~~>
  ~~~~
</bean>

<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource1"/>
</bean>
<bean id="transactionManager2" class="~~나머지는 동일>
</bean>

<tx:annotation-driven transaction-manager="transactionManager1"/>
<tx:annotation-driven ~~동일/>

발생했던 오류 상황

1. 2번째 Database를 사용하는 mapper bean injection 시 2개의 sessionFactory가 발견되어 매칭 불가 상황

  => mapper에 2번째 DB sessionFactory를 강제 주입(Qualifier 어노테이션 이용)
<bean id="Mapper bean명" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="dataSource2를 사용하는 Mapper 인터페이스 위치"/>
  <property name="sqlSessionFactory" ref=sqlSessionFactory2"/>
</bean>
 그리고 mapper interface위에 Qualifier("Mapper bean명") 설정하여 해결 완료

Posted by 知彼知己百戰不殆
,