[Spring] MyBatis Batch + Transaction 을 이용한 대용량 SQL작업


마을에서 오크잡는 퀘스트 하고 있는데 갑자기


중간보스를 잡아오라는 퀘스트가 떨어졌다...



일정시간마다 라즈베리파이에서 받아온 원시데이터를 재가공하여


DB에 insert 해주어야 하는 작업


로우수가 적다면 그냥 만들겠지만 대용량 작업일 경우 답이 안나온다.


약 1만건~10만건 정도의 데이터를 날려줘야 하는데 ㅂㄷㅂㄷㅂㄷ


그래서 찾아본 방법은 Batch와 Transaction 을 이용한 대용량 sql 작업



나도 정확히 내가 뭘 한건지도 모르고 그냥 스택오버 플로우, 오키, 전자정부 뒤적거리면서 이것 저것 다 때려 박느라

필요 없는 설정이 있을 수도 있으니 아는 사람은 댓글좀 달아주시길 바랍니다.



1.  XML 설정


1) mapper 설정

context-mapper.xml 파일이나 context-sqlMap.xml 파일에


마이바티스 연동을 위해 만들어놨던 설정을 아래와 같이 바꿔준다.


9번 라인의 batch설정으로 batch 사용이 가능 하도록 하는 듯 하다.


1
2
3
4
5
6
7
8
9
10
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/egovframework/sqlmap/example/sql-mapper-config.xml" />
        <property name="mapperLocations" value="classpath:/egovframework/sqlmap/example/mappers/mssql/*.xml" />
    </bean>
 
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
        <constructor-arg index="0" ref="sqlSession" />      
        <constructor-arg index="1" value="BATCH" />
    </bean>
cs



2) datasource 설정

DB접속 정보 작성하는 곳에 트렌젝션메니저 설정을 하는데 이걸 해야 하는 건진 잘 모르겠다.


1
2
3
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
cs



3) dispatcher-servlet 설정


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:task="http://www.springframework.org/schema/task" 
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-4.0.xsd
                http://www.springframework.org/schema/task
                http://www.springframework.org/schema/task/spring-task.xsd
                http://www.springframework.org/schema/mvc 
                http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 
 
<tx:annotation-driven proxy-target-class="true"/>
cs


7번 라인과 17번 라인을 추가해주고 20번라인의 내용을 넣어 주도록 한다.



4) pom.xml


1
2
3
4
5
6
7
8
<!-- 트랜젝션 처리를 위함 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
cs



디펜던시에 추가를 해줘야 트랜젝션 처리가 가능한건진 모르겠음. 전자정부 자체에 관련된게 이미 추가 되어 있을 수도 있고

정확히 모르겠음 저건



2. DAO or impl 작성


나는 DAO를 사용하지 않고 공통DAO하나 만들어 놓고 impl에서 바로 쿼리를 날려주는 방식을

좋아 한다.


어차피 DAO에서 특별히 해줄것도 없고.. 해줘야 하는것이 있어도 impl에서 해주면 되니까



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
    public void updateSchedulerHistoryRow(List<MinHistoryVO> historyList) {
        // TODO Auto-generated method stub
        
       // 트렌젝션 시작
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        long startTime = System.currentTimeMillis();
            try {
                
                for (MinHistoryVO list : historyList) {                     
                    sqlSession.update("scheduler.updateSchedulerHistoryRow", list);
                }
 
            } finally {
                sqlSession.flushStatements();
                sqlSession.close();
            }
 
        long endTime = System.currentTimeMillis();
        long resutTime = endTime - startTime;
        System.out.println("트랜젝션 배치" + " 소요시간  : " + resutTime/1000 + "(ms)");
    }
cs



난 이런식으로 작성 했다.


가끔 6번 라인에 ExecutorType.BATCH 이 매개변수를 안넣고 시작 할 수 있는데

그러면 트렌젝션 안돌고 커넥션 다 찍으면서 돌게 된다.


저렇게 해도 수만건이 돌게 되면 세션에저장될 데이터들이 넘쳐흘러서 그런지 버벅거릴때가 있는데


그럴땐 컨트롤러에서 조금씩 끊어서 날려 주도록 하자



3. controller


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
        //컨트롤러에서 일정 개수 단위로 끊어서 날려 준다.
        int insertCount = 0;
        List<MinHistoryVO> divHisList  = new ArrayList<MinHistoryVO>();
        for(int hisCount = 0, hisSize = historyList.size(); hisCount < hisSize; hisCount++){
            MinHistoryVO _tempData = new MinHistoryVO();
            _tempData = historyList.get(hisCount);
            divHisList.add(_tempData);
            if(insertCount == 1000 || hisSize-1 == hisCount){
                schedulerService.updateSchedulerHistoryRow(divHisList); // 트렌젝션
                divHisList =  new ArrayList<MinHistoryVO>();
                insertCount = 0;
            }
            else{                    
                insertCount++;
            }
        }
cs



while문 사용하는게 익숙하지 않아서 나는 for문을 주로 사용 한다.

리스트에 잔뜩 있는 데이터들을 새로운 작은 바구니에 담아서 끊어서 날려준다.








이렇게 하면 MsSql Server 2005버전 기준 1만건 insert하는데 5초정도 걸린다.


저기에  마이바티스 foreach까지 써서 벌크인서트 하면 시간은 더 단축 된다.


원시데이터를 쪼개서 60개컬럼에 따로 박아야 하기 때문에


넘겨주는 파라미터 개수 2100개 제한이 있어서 제대로 사용 못했는데


여러개로 쪼갠다음에  Mybatis foreach 돌려서 한번에 날려주면 시간은


훨씬 더더더더더 단축 된다.





oracle MyBatis에서 다중 Insert 하는 방법



mssql에서 oracle로 마이그레이션을 하는 도중 하나의 맵핑된 쿼리 안에서


여러개의 행을 insert하는 것에서 문제가 발생했다


mssql을 사용할떈 그냥 insert문을 여러개 쓰는것 만으로 한번에 여러 행을 입력 할 수 있었는데


오라클에선 구문오류가 발생하게 된다.


그렇게 방법을 찾다가 발견한 방법은


INSERT ALL 이다



사용법은 아주아주 굉장히 간단하다.


일단 MyBatis에서 여러 데이터를 맵형태로 보내 다이나믹 쿼리로 만드는 방법은


아래 링크를 참고하고

2015/07/09 - [Yame Programmer/전자정부프레임워크] - [ibatis] 동적쿼리 생성 및 outOfBoundsException 에러


ibatis와 mybatis의 사용방법이 상이하긴 하지만 맥락은 같으니 참고하면 좋을 것이다.




쿼리문은 아래와 같이 사용 하면 된다.


1
2
3
4
5
6
7
8
9
10
    <insert id="insertMtrlOrderList" parameterType="java.util.Map">
        <foreach collection="list" item="item" index="index"  open="INSERT ALL " separator=" " close="SELECT * FROM DUAL" 
         into FM_MATERIALS_ORDER_LIST(MTRL_ID, MTRL_ORDER_ID, 
            MTRL_ENTERPRISE, UNIT_COST, MTRL_ORD_QUANTITY, APPLY_DATE)
        values
            (#{item.MTRL_ID}, #{item.MTRL_ORDER_ID}, 
        #{item.MTRL_ENTERPRISE}, #{item.UNIT_COST}, 
        #{item.MTRL_ORD_QUANTITY}, SYSDATE)
        </foreach>
    </insert>
cs



시작할떄 INSERT ALL 을 써주고 본 쿼리으 insert문은 insert를 제외한 into부터 시작해서 작성하면 끝


역시 사람은 아는게 많아야 손발이 고생을 안하는 것 같다.




간단하다 mybatis에 써놓은 쿼리중에 #{변수} << 이부분 이름 틀린거


예를들어 VO엔


1
2
3
4
5
6
7
8
9
    private String FLOOR_PEOPLE;//
    
    public String getFLOOR_PEOPLE() {
        return FLOOR_PEOPLE;
    }
    public void setFLOOR_PEOPLE(String fLOOR_PEOPLE) {
        FLOOR_PEOPLE = fLOOR_PEOPLE;
    }
 
cs


이렇게 되어있는데


쿼리 작성시엔 아래와 같이 대소문자를 다르게 썻다던가


1
2
3
4
5
UPDATE EASY_COMMON.CM_FLOOR_INFO
        SET 
            FLOOR_NAME = #{FLOOR_NAME},
            FLOOR_PEOPLE = #{FLOOR_people}
        WHERE FLOOR_ID = #{FLOOR_ID}
cs


혹은 다른 이름을 썻다던가 할때 발생하는 에러이다.


한꺼번에 특정 문자열을 바꾸는 작업후에 발견되는 경우가 종종 있다.


org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'EASY_COMMON' in 'class egovframework.easyplatform.common.place.space.vo.SpaceVO'

at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) ~[mybatis-spring-1.2.0.jar:1.2.0]

at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:364) ~[mybatis-spring-1.2.0.jar:1.2.0]

at com.sun.proxy.$Proxy84.selectList(Unknown Source) ~[?:?]

at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:194) ~[mybatis-spring-1.2.0.jar:1.2.0]

at egovframework.rte.psl.dataaccess.EgovAbstractMapper.selectList(EgovAbstractMapper.java:238) ~[egovframework.rte.psl.dataaccess-3.5.0.jar:?]

at egovframework.easyplatform.common.setting.standardsetting.service.impl.SpaceSettingServiceImpl.insertSpace(SpaceSettingServiceImpl.java:30) ~[classes/:?]

at egovframework.easyplatform.common.setting.standardsetting.web.SpaceSettingController.insertSpace(SpaceSettingController.java:71) ~[classes/:?]

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_91]

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_91]

at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_91]

at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:747) ~[spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:676) ~[spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) [spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870) [spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) [spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863) [spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at javax.servlet.http.HttpServlet.service(HttpServlet.java:650) [servlet-api.jar:?]

at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) [spring-webmvc-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) [servlet-api.jar:?]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) [catalina.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.69]

at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat7-websocket.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.69]

at egovframework.easyplatform.common.interceptor.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:26) [classes/:?]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.69]

at egovframework.rte.ptl.mvc.filter.HTMLTagFilter.doFilter(HTMLTagFilter.java:52) [egovframework.rte.ptl.mvc-3.5.0.jar:?]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.69]

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [spring-web-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.0.9.RELEASE.jar:4.0.9.RELEASE]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.69]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.69]

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.69]

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.69]

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) [catalina.jar:7.0.69]

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169) [catalina.jar:7.0.69]

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.69]

at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956) [catalina.jar:7.0.69]

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.69]

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:436) [catalina.jar:7.0.69]

at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078) [tomcat-coyote.jar:7.0.69]

at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625) [tomcat-coyote.jar:7.0.69]

at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) [tomcat-coyote.jar:7.0.69]

at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_91]

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_91]

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.69]

at java.lang.Thread.run(Unknown Source) [?:1.8.0_91]

Oracle 부적합한 열유형 null 처리 jdbcType=VARCHAR를 사용하지 않고 해결하는 방법


mssql로 만들어진 프로젝트를 Oracle로 마이그레이션 작업을 하던 도중 어마어마한 노가다 작업에 봉착했다


Oracle 사용시 Null 허용컬럼에 값이 null이 들어가는 경우


부적합한 열 유형 이라는 에러 메세지가 뜨게 된다.


이때 이를 해결하기 위해서 


value1 = #{value1, jdbcType=VARCHAR},

value2 = #{value2, jdbcType=VARCHAR}


이런식으로 값 뒤에  , jdbcType=VARCHAR]  를 붙이게 되는데 


생각해보니 이게 양이 너무나도 많은것이다. 이걸 하나하나 언제 다 수정하고 앉아있을까


그래서 구글링해서 찾아낸 방법이 있다.


단 이것은 자신이 mybatis 설정파일을 변경할 권한이 있는 경우 사용하길 바란다.



1. mybatis-config.xml 파일을 연다. 만약 없는 경우

전자정부 프레임워크를 사용한다면 context-sqlMap.xml 파일을 열어 보면


1
2
3
4
5
6
7
8
9
10
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:/egovframework/sqlmap/example/sql-map-config.xml" />
        <!-- <property name="mapperLocations" value="classpath:/egovframework/sqlmap/example/sample/PostgreSQL.xml" />
        
        <property name="configLocation" value="classpath:/mapper/mybatis-config.xml" /> -->
        <!-- Core File관련 Table SQL MAP 설정 위치 -->
        <!-- DB변동시 sql 맵퍼 패턴 수정 -->
        <property name="mapperLocations" value="classpath:/egovframework/sqlmap/example/mappers/${Globals.Mapping}"    /
    </bean>
cs



이런 부분이 있는데 여기서  프로퍼티 네임이 configLocation 인것을 찾는다


value값에 보면 컨피그로케이션의 경로가 있는데 저 경로에 찾아가면


아마 mybatis 설정하는 부분이 있거나 typeAlias를 선언해 주는 부분일텐데 일단 해당 파일을 연다




2. configuration 태그 아래 settings 이라는 태그가 있는지 확인


3. 없으면 직접 설정한다


4. 있던 없던 아래와 같은 셋팅 프로퍼티를 추가 한다.


1
2
3
4
5
6
<!--  oracle null 처리  -->
    <settings>
        <setting name="cacheEnabled" value="false" />
        <setting name="jdbcTypeForNull" value="NULL" />
    </settings>
 
cs




그럼 이제 저 귀찮음 많은 jdbcType=VARCHAR 선언들을 해주지 않아도 된다!


역시 개발자는 귀찮은거 싫어하고 머리를 굴려야 한다는걸 다시 깨닫게 된다.


쿼리를 작성하다 보면 부등호 (>,<) 를 사용해야 할 때가 있다. 그러나 mybatis에서 사용하면 에러가 나는데


이때 해결방법을 알아 보자.




쿼리에 부등호 기호를 사용하면  


The content of elements must consist of well-formed character data or markup.


라는 경고문구가 나타나기도 한다.


부등호 이외에도 '&' 같은 특수기호에서도 나타난다


이때 해결방법은 간단하다


<![CDATA ]]> 를 사용하면 된다.



1
2
3
4
5
6
7
8
9
10
11
12
13
<select id="loadCartList"  parameterType="userInfoVO" resultType="cartVO">
    
    <![CDATA
    SELECT
        *    
    FROM
        table_name
    WHERE
        coulumA < 10
    AND 
        coulumB > 4
    ]]>
    </select>
cs



이렇게 쿼리를 CDATA로 감싸주면 된다.


혹은


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="loadCartList"  parameterType="userInfoVO" resultType="cartVO">
    
    SELECT
        *    
    FROM
        table_name
    
    WHERE
    <![CDATA
        coulumA < 10
    AND 
        coulumB > 4
    ]]>
    </select>
cs




이런 식으로 사용 할 수도 있다.



방금 댓글을 남겨주신 분이 추가 정보를 달아주셨다


> - &gt;
< - &lt;
>= - &gt;=
<= - &lt;=


CDATA를사용하지 않고 저렇게 HTML에서 사용하던 방식으로도 치환이 가능 하다



1
2
3
4
5
6
7
8
9
10
11
12
13
<select id="loadCartList"  parameterType="userInfoVO" resultType="cartVO">
    
    SELECT
        *    
    FROM
        table_name
    
    WHERE
        coulumA &lt; 10
    AND 
        coulumB &gt; 4
    </select>
 
cs


흔하게 실수 할 수 있는 spring mybatis 에러

Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener



만약 당신이 전자정부 프레임워크를 사용하거나 spring 프레임워크 mybatis를 사용하고 있으며


typealias를 매핑형식으로 sql-map-config.xml에서 관리를 하는데 새로운 쿼리를 추가 하거나

 

typealias를 추가 했는데 서버를 구동시키자 저런 흉악한 에러메세지를 뿜어낸다면 그리고 분명히


경로를 제대로 복사 하였는데도 해당 VO클래스를 찾지 못한다는 에러 메세지가 나타난다면 1개만 더 확인 해 보자.


<typeAlias type="egovframework.easyplatform.common.tree.TreeDataVO" alias="treeDataVO" /> 


<typeAlias type="egovframework.easyplatform.commonvo.tag.vo.ExtendTagDicVO " alias="extendTagDicVO" />





위의 두 vo설정 코드에서 이름과 경로가 다르다는 것 외의 또하나의 차이점을 발견 하였는가?


저기서 둘중 하나의 코드때문에 vo를 찾지 못하는 에러가 나타나게 된다.


아직 모르겠다면 아래쪽의 코드를 잘 살펴 보도록 하자


그것은 경로가 들어가야 하는 부분에 포함되어 있는 공백 때문이다.

<typeAlias type="egovframework.easyplatform.commonvo.tag.vo.ExtendTagDicVO " alias="extendTagDicVO" />

<typeAlias type="egovframework.easyplatform.commonvo.tag.vo.ExtendTagDicVO" alias="extendTagDicVO" />


이렇게 보면 좀더 확인 하기 쉬울 것이다.


vo클래스의 경로를 넣어 주는 부분에 복사 붙여넣기를 하다보면 공백이 들어가는 경우가 종종 생긴다.


그럴때 분명히 경로는 맞는데 왜 클래스를 찾지 못하는지 모르겠다면 공백이 들어가있는지를 확인해 보도록 하자.






심각: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'alarmService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private egovframework.경로.GenericDao egovframework.easyplatform.common.alarm.service.impl.AlarmServiceImpl.genericDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericDao': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSession' defined in file [C:\eGovFrameDev-3.5.1-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps\easy-common\WEB-INF\classes\egovframework\spring\context-sqlMap.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [egovframework/sqlmap/example/sql-map-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework.경로.tag.vo.ExtendTagDicVO

at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:301)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)

at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)

at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)

at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)

at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5068)

at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5584)

at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)

at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1572)

at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1562)

at java.util.concurrent.FutureTask.run(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private egovframework.경로.generic.GenericDao egovframework.easyplatform.common.alarm.service.impl.AlarmServiceImpl.genericDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericDao': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSession' defined in file [C:\eGovFrameDev-3.5.1-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps\easy-common\WEB-INF\classes\egovframework\spring\context-sqlMap.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [egovframework/sqlmap/example/sql-map-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework경로.tag.vo.ExtendTagDicVO

at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:522)

at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)

at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:298)

... 22 more

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'genericDao': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSession' defined in file [C:\eGovFrameDev-3.5.1-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps\easy-common\WEB-INF\classes\egovframework\spring\context-sqlMap.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [egovframework/sqlmap/example/sql-map-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework경로.tag.vo.ExtendTagDicVO

at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:308)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1021)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:964)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:862)

at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:494)

... 24 more

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSession' defined in file [C:\eGovFrameDev-3.5.1-64bit\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps\easy-common\WEB-INF\classes\egovframework\spring\context-sqlMap.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [egovframework/sqlmap/example/sql-map-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework.경로.tag.vo.ExtendTagDicVO

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1554)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)

at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)

at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:450)

at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:424)

at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:549)

at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:178)

at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)

at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:305)

... 35 more

Caused by: org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [egovframework/sqlmap/example/sql-map-config.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework경로.tag.vo.ExtendTagDicVO

at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:430)

at org.mybatis.spring.SqlSessionFactoryBean.afterPropertiesSet(SqlSessionFactoryBean.java:336)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1613)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1550)

... 47 more

Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework.경로.tag.vo.ExtendTagDicVO

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:106)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:89)

at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:424)

... 50 more

Caused by: org.apache.ibatis.builder.BuilderException: Error registering typeAlias for 'extendTagDicVO'. Cause: java.lang.ClassNotFoundException: Cannot find class:  egovframework.경로.tag.vo.ExtendTagDicVO

at org.apache.ibatis.builder.xml.XMLConfigBuilder.typeAliasesElement(XMLConfigBuilder.java:127)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:96)

... 52 more

Caused by: java.lang.ClassNotFoundException: Cannot find class:  egovframework.경로.tag.vo.ExtendTagDicVO

at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:188)

at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:87)

at org.apache.ibatis.io.Resources.classForName(Resources.java:254)

at org.apache.ibatis.builder.xml.XMLConfigBuilder.typeAliasesElement(XMLConfigBuilder.java:120)

... 53 more

+ Recent posts