[에러] no matching editors or conversion strategy found


1. 환경                                                         

                         

 Spring 

 4.3.6 (SpringMVC 기준)

 Java 

 1.8.0_92

 Tomcat 

 8.0.42

 암호화 관련 라이브러리

 jasypt-spring31-1.9.2.jar

 jasypt-1.9.2.jar

 bcprov-jdk15on-1.56.jar

 bcpkix-jdk15on-1.56.jar

            


2. 에러 메세지


 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configurationEncryptor' defined in file [C:\sample\server\apache-tomcat-8.0.42\webapps\sample-pjt\WEB-INF\classes\META-INF\config\context-datasource-dev.xml]: Cannot resolve reference to bean 'environmentVariablesConfiguration' while setting bean property 'config'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'environmentVariablesConfiguration' defined in file [C:\Sample\server\apache-tomcat-8.0.42\webapps\sample-pjt\WEB-INF\classes\META-INF\config\context-datasource-dev.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'java.security.Provider' for property 'provider'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.security.Provider' for property 'provider': no matching editors or conversion strategy found



3.  AS-IS 설정/소스

 

    - database 관련 설정파일 context-datasource.xml 파일 내 프로퍼티 파일 암호화 환경 설정

   

   <!-- 암호화  provider 선언 -->

    <bean id="bouncyCastleProvider" class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>

    <!-- 암호화  환경 설정 -->

    <bean id="environmentVariablesConfiguration"

        class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">

        <property name="provider" value="bouncyCastleProvider" />

        <property name="algorithm" value="PBEWITHSHA256AND128BITAES-CBC-BC" />

        <property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />

    </bean>

    <!-- 암호화 실행 모듈 선언 -->

    <bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">

        <property name="config" ref="environmentVariablesConfiguration" />

        <property name="password" value="easyframework" />

    </bean> 



4. 에러 원인


    - environmentVariablesConfiguration bean에서는 bouncyCastleProvider 라는 bean을 참조로 하여 암호화 환경을 설정하고 있는데,

       이때, provider 속성에 해당하는 참조 bean bouncyCastleProvider를 'ref'로 선언해야 하는 데 value 로 선언하여 이를 provider 속성에

       String 값으로 넣으려 하다가 나는 에러다. 객체를 참조하는 부분이니 value 가 아니라 ref로 바꿔줘야 정상 동작한다. ㅎㅎㅎ 이런 실수를 ㅜ

       처음보는 에러 메세지여서 정리해둔닷



5. 해결


    - 아래와 같이 설정 변경해주니, 정상 기동하였다.


  <!-- 암호화  provider 선언 -->

    <bean id="bouncyCastleProvider" class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>

    <!-- 암호화  환경 설정 -->

    <bean id="environmentVariablesConfiguration"

        class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">

        <property name="provider" ref="bouncyCastleProvider" />

        <property name="algorithm" value="PBEWITHSHA256AND128BITAES-CBC-BC" />

        <property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />

    </bean>

    <!-- 암호화 실행 모듈 선언 -->

    <bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">

        <property name="config" ref="environmentVariablesConfiguration" />

        <property name="password" value="easyframework" />

    </bean> 




'Spring' 카테고리의 다른 글

(작성중) dispatcher-servlet.xml 설정  (0) 2017.04.16
spring - profile  (0) 2017.03.19
[Spring] Transaction 관리  (0) 2017.03.12
Spring - BeanNameViewResolver  (0) 2017.01.29


프로젝트에서 전체 프로젝트 환경 구성을 맡게 되었다. 

프로젝트 구조를 어떻게 가져갈지 고민하고, 패키지 구조, 공통 제공 기능 등을 구상해야 했다. 

처음해보기도 했고, 아직 많~~~~이 부족하다는 걸 매순간 깨닫는 작업이었다..  

프로젝트 끝나기 전까지 내가 스스로 프로젝트를 좀 더 효율적으로 할 수 있는 부분을 캐치해내고, 적용해보는 부분이 생기도록 고민해봐야겠다!


우선, 오늘은 Spring 설정 부분을 정리해두려 한다. 

구성한 프로젝트 환경은 아래와 같다


 - JAVA: JDK 1.8

  - IDE: Eclipse Mars2 (4.5)

  - WAS: Tomcat 8.0.42 

  - DB: Oracle 11g

  - Build: Maven 3.3.9

  - Framework: Spring 4.3.6 , 사내프레임워크

 


기존 시스템 재구축 성격의 프로젝트라, 기본적인 tools 업그레이드와, 프레임워크 버전 현행화가 요새 주된 작업이다.

버전 업그레이드라 생각해서 처음부터 구축하는 것 보다 낫겠지 싶었는데, 더 어려운 것 같다.. 호환성이 안맞아 깨지는 부분이 생기고 ㅜ


AS-IS 시스템은 Spring 3.1 버전을 쓰고 있었다.


Spring 4.3.x 에 맞게 dispatcher-servlet.xml 파일을 수정했다. 처음엔 뜬구름 잡듯이 이해됬었는데, 차장님한테 질문하고나니

그래도 흐름이 쭉 잡힌 것 같다. 잘정리해놔야지!


_____________________________________________________________________________________________________________________________

# Spring 설정: dispatcher-servlet.xml


  dispatcher-servlet에서 기본적으로 설정 고려해야 하는 항목들은 아래와 같다고 생각한다.

  

  1.component 스캔

   2.MVC 설정 = interceptors, adpater, handler

   3.Resolver 설정


 '화면'단에 적용할 설정들을 모아놓는 곳이기 때문에 기본적으로 위의 설정들은 들어가야 한다. 


1) dispatcher-servlet.xml

  

    - 톰캣 서버를 기동시키면 기동로그에 dispatcher-servlet 파일이 로딩되는 부분이 보인다.

    - root Context 초기화가 이루어진 다음, 이제 WebApplication Context가 초기화될 차례다.

    -  WebApplication Context가 초기화되면서, dispatcher-servlet.xml 파일에 선언한 bean 들이 등록된다.


정보: Initializing Spring FrameworkServlet 'sample'

| [INFO ] 20:45:38.727 [o.s.w.servlet.DispatcherServlet] [localhost-startStop-1]   -FrameworkServlet 'sample': initialization started 

| [INFO ] 20:45:38.732 [o.s.w.c.s.XmlWebApplicationContext] [localhost-startStop-1]   -Refreshing WebApplicationContext for namespace 'sample-servlet': startup date [Sun Apr 16 20:45:38 KST 2017]; parent: Root WebApplicationContext 

| [INFO ] 20:45:38.732 [o.s.b.f.x.XmlBeanDefinitionReader] [localhost-startStop-1]   -Loading XML bean definitions from class path resource [META-INF/dispatcher-servlet.xml]  



  (1) component 스캔 작업


      - dispatcher-servlet.xml 파일 내 컴포넌트 스캔 셋팅은 아래와 같다. 


<?xml version="1.0" encoding="UTF-8"?>

<beans  xmlns:context="http://www.springframework.org/schema/context" 

            xsi:schemaLocation=" http://www.springframework.org/schema/context 

                                         http://www.springframework.org/schema/context/spring-context.xsd ">


<context:component-scan base-package="com.sampleframework, com.sampleCompany.sample" use-default-filters="false">

   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>    

</context:component-scan>  



      ▶ Spring이 @Component 또는 @Component를 메타 어노테이션으로 갖고 있는 어노테이션(@Controller, @Repository, @Service)이 

          붙은 클래스들을 빈으로 등록한다.

      ▶ 스캔 범위: 보통 공통빈(persistence, service) 설정 정보는 Application context에, web layer 단의 빈(controller)들WebApplicationContext에 

                        저장한다.

      ▶ stereotype annotation: 클래스에 붙어 해당 클래스가 컴포넌트 스캔 대상이고, 스프링에 의해 관리될 것임을 명시한다. 

      ▶ base-package: 설정한 패키지 내에서 컴포넌트 스캔을 수행한다. 스캔 범위 지정

      ▶ use-default-filters: 아무 설정을 안할 경우 default로는 모든 stereo type 스캔한다. 개별적으로 특정 빈만 스캔하려는 경우 

                                   해당 설정을 false로 해주고, 특정 빈을 include filter 설정해주어야 한다.



      ▶ sts 의 spring explorer를 통해 bean 로딩 확인 (프로젝트 패키지명은 모자이크 처리함)



[ 이미지1 - component-scan의 use-default-filters 설정을 주지 않은 경우, base-package내 컴포넌트들을 모두 스캔하고 있다]



                   [ 이미지2 - component-scan의 use-default-filters 설정을 false로 주고, Controllerㄹ 컴포넌트만 include 설정 한 경우, base-package내 

                                  @Controller 컴포넌트들만 스캔하고 있다]




(2) spring MVC 설정


    - spring MVC를 활성화하기 위해 아래와 같은 설정을 해준다.


    - 보통 설정들을 copy해서 쓰기 때문에 실제로 이 설정이 정확히 어떤 역할을 하는지 몰라 그냥 그대로 쓰는 경우가 많다.

      그러다 보면 사용하지 않는 설정들도 다 포함되어 설정파일만 비대해지게 된다. 


      STS를 별도로 설치하여 spring explorer 뷰를 활용하여 실제 설정을 적용했을 때 어떤 변화가 일어나는 지 확인해 보았다. (강추!)

      (eclipse Mars2 4.5 버전에서는 sts 플러그인 설치 시, 기존 내장되어 있는 maven 의 m2e와 충돌이 나는지.. 설치 후 

       maven 도 안되고, sts 기능도 사용이 불가했다...버그인것 같은데 레퍼런스가 거의 없다 ㅜㅜ. sts 중 maven 과 겹치는 부분은 제외한 채

       설치해도 같은 결과가 반복됬다.....eclipse를 밀기를 몇번 ^^;; 그냥 sts 를 별도로 설치해서 확인했다)


<mvc:annotation-driven />  


    ▶@Controller 와 @RequestMapping 사용 활성화

    ▶@Controller들에게 요청을 전파하기 위한 HandlerMapping(default: RequestMappingHandlerMapping)과          

       HandlerAdapter(default: RequestMappingHandlerAdapter)를 등록


         - RequestMappingHandlerMapping 역할: 요청들을 해당 annotation이 걸린 컨트롤러 method로 매핑

          

    ▶ HandlerExceptionResolver 등록

  


[이미지3 - mvc:annotation-driven 설정을 해준 경우, 위와 같이 handlerAdapter가 자동으로 등록되었다. 더 깊게 확인은 못해봤지만,       

              AnnotationDrivenBeanDefinitionParser라는 애가 파싱을 담당하나 보다.]





(3) MVC - interceptor 설정 


(4) MVC - adapter 설정


(5) MVC - resolver 설정






__________________________________________________________________________________________________________________________________________________________

** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :) 

** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.



 

      


'Spring' 카테고리의 다른 글

[에러] no matching editors or conversion strategy found  (0) 2017.04.20
spring - profile  (0) 2017.03.19
[Spring] Transaction 관리  (0) 2017.03.12
Spring - BeanNameViewResolver  (0) 2017.01.29

 [Spring] 


# Profile 기능


1) spring profile 이란?


    - Spring Profiles provide a way to segregate parts of your application configuration and make it only available in certain 

        environments. Any @Component or @Configuration can be marked with @Profile to limit when it is loaded

     - 어플리케이션의 여러 환경들을 설정해놓고 필요시마다 원하는 환경으로 선택 구동하게끔 설정해주는 기능.

     - Spring 3.1 부터 등장한 기능으로, 환경 별로 다른 profile을 적용할 수 있게 하는 기능.

     - 주로 어플리케이션 개발/테스트/운영 환경 설정에 자주 쓰인다.



2) 설정 방법


     (1)application context 의 beans 에 환경 별 profile 등록


 <beans profile="dev">

     <bean id="" class="">

          <property name="" value=""/>             --> 개발환경 profile

     </bean>

 </beans>

 <beans profile="prd">

<bean id="" class="">

          <property name="" value=""/>             --> 운영환경 profile

     </bean>

 </beans>    



    (2) 등록한 bean 중 구동할 profile 선택 활성화

          

         방법1) JVM property로 설정

                  : tomcat 서버 더블 클릭 > open launch configuration > arguments 탭 > VM arguments 에 아래 설정 추가 

                                

 -Dspring.profiles.active=dev       --> 개발환경 용 profile 활성화 시 



         방법2) web.xml 에 설정


 <context-param>

    <param-name>spring.profiles.active</param-name>

    <param-value>dev</param-value>

 </context-param>



         방법3) annotation 으로 설정

                       : 설정 파일에 각 환경별로 설정한 후, @Configuration + @Profile("설정한환경 value") 로 구동할 수 도 있다.

                                                                                  @ContextConfiguration("/context-common.xml") + @ActiveProfiles("dev")  

                                                                                       --> junit 등으로 test case 돌릴 때 유용

   

 @Configuration 

 @Profile("dev") 

 public class SampleClass {

   .....

 }




         방법4) programming으로 설정

                   : 어플리케이션 구동 전SpringApplication.setAdditionalProfiles() 를 사용하거나

                     , spring이 제공하는 인터페이스 ConfigurableEnvironment 를 통해 설정하여  활성화 할 profile 설정





__________________________________________________________________________________________________________________________________________________________

** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :) 

** 본 포스팅은 아래의 reference 들을 참고하여 내용을 덧붙인 글입니다. 혹시, 문제가 되는 경우 알려주시면 조치하도록 하겠습니다.

** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.


  - http://docs.spring.io/spring-boot/docs

  - http://www.lesstif.com/

 

'Spring' 카테고리의 다른 글

[에러] no matching editors or conversion strategy found  (0) 2017.04.20
(작성중) dispatcher-servlet.xml 설정  (0) 2017.04.16
[Spring] Transaction 관리  (0) 2017.03.12
Spring - BeanNameViewResolver  (0) 2017.01.29

# Spring - Transaction


1) Transaction 이란?


    - 데이터베이스 관리 시스템에서의 상호작용 단위

    - 데이터베이스 작업 단위

    - 하나 이상의 SQL 문장들로 이루어진 논리적인 작업 단위

    - 데이터베이스 처리 작업이 모두 완료되거나 모두 취소되게 되는 작업의 단위


     --> 실제로 INSERT, UPDATE, DELETE 등 도 하나의 트랜잭션으로 볼 수 있다.  예를 들어, 10개의 데이터를 삭제 하는 경우 3개를 삭제한 후,

          4개째에서 오류가 발생하여 삭제가 안되면, 기존의 삭제 된 3개도 rollback 한다. (또는 3개만 정상 삭제 처리됬다고 사용자에게 알림을 

          주기도 한다)


     --> 여러개의 DML 문을 복합적으로 사용하여 하나의 트랜잭션으로 묶는 경우도 많다. DELETE 후 INSERT 하는 경우가 그 예이다. 



2) Transaction의 특성 'ACID'

  

    - 원자성(Atomicity): 더이상 분리할 수 없는 하나의 작업 단위로, 모두 완료되거나 모두 취소되어야 한다.


    - 일관성(Consistency): 사용되는 데이터는 모두 일관되어야 한다.


    - 고립성(Isolation): 하나의 트랜잭션이 접근하고 있는 데이터는 다른 트랜잭션으로 부터 격리되어야 한다. 

                             트랜잭션 과정 중간의 데이터는 확인 불가.


    - 영구성(Durability): 트랜잭션이 종료되면, 그 결과는 영구적으로 적용되어야 한다.


       --> 실제론, 성능향상을 위해 각 특성을 완화하는 경우도 많다. 



 3) Transaction, 뭐 때문에 쓰는건지?? 목적?


     트랜잭션을 쓰는 이유는 데이터 무결성(integrity) 때문이다. 

     쿼리 하나가 실패하면, 데이터베이스 시스템은 전체 트랜잭션 또는 실패한 쿼리를 롤백한다. 

     은행에서 내계좌에서 돈이 빠져나간 후 '송금' 처리하는 작업을 순차적으로 처리할 때, 중간에 쿼리가 실패하여

     내 계좌에서는 돈이 빠져나갔는데, 송금 처리는 되지 않는 경우가 발생 할 수 있다. 이런 경우 데이터 무결성이 깨지게 된다. 

     이러한 문제를 방지하기 위해서, 즉 데이터 무결성을 지키기 위해 트랜잭션을 사용한다.

     

     --> 실제로 트랜잭션은 보통 아래와 같은 과정을 거쳐 SQL 언어로 데이터베이스 내에서 실행된다.

            * Begin the transaction

            * Execute several queries  (DB 갱신 전)

            * Commit the transaction  (성공적인 트랜잭션 수행 후, DB 갱신)



  4) Transaction 설정


      사실 이 부분을 정리해 두려고, 이 포스팅을 작성하기 시작했다. 프로젝트 때 delete 후 insert 하는 업무 등을 처리하기 위해

      트랜잭션을 걸어줬었다. 실제로 어떻게 설정하는지 아래에 정리해 보았다.


      트랜잭션을 설정하는 방법은 하나만 있는 것이 아니다. Java의 트랜잭션 API (JTA)를 쓸 수도 있고, Spring이 제공하는 트랜잭션

      기능 등을 이용할 수 도 있다. 


      우선 이번 포스팅에서는 Spring에서 제공해주는 트랜잭션 관리 방법을 정리하고자 한다. 



 (4.1) Transaction 관련 스키마 설정

      

<?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:tx="http://www.springframework.org/schema/tx"

        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">



 (4.2) TransactionManager 설정


         - 우선, datasource 쪽 설정파일에 transactionmanager 설정을 해준다.

         - 이번 프로젝트에서는, resources/spring/context-datasource.xml 이라고 DB 관련 설정을 한 데 모아놓았다. 트랜잭션도 이곳에 설정!

         - class: spring 프레임워크에서 제공하는 DataSourceTransactionManager 클래스 (platformTransactionManager)


<tx:annotation-driven transaction-manager="transactionManagerSample" proxy-target-class="true" />

     <bean id="transactionManagerSample"       

              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

         <property name="dataSource" ref="dataSourceSample" />

     </bean>

tx:annotation-driven

 어노테이션에 기반한 트랜잭션의 동작을 활성화한다

 @Transcational이 붙은 bean 만 찾음 (applicationContext에서)

   --> 만약 webApplicationContext에 tx:annotaion-driven을 설정해놓으면 서비스가 아니라 controller

         에서만 @Transcational이 붙은 bean을 찾는다

transaction-manager

 default 값: transactionManager

 default 값 'transactionManager' 가 아닌 다른 이름을 사용하는 경우에만 설정 

 proxy-target-class

 proxy 모드에만 적용된다.
 @Transactional 어노테이션이 붙은 클래스에 어떤 타입의 트랜잭션 프록시를 생성할 것인지 제어한다.    proxy-target-class 속성을 true로 설정했다면 클래스기반의 프록시가 생성된다.
  --> 트랜잭션은 원래 interface에다가 걸게끔 나왔는데, controller 클래스에 걸려는 사용자들이 늘어나

       면서 기본 클래스에도 transaction을 걸 수 있도록 설정할 수 있게 되었다. 

 proxy-target-class 속성을 생략하거나 false로 설정하면 표준 JDK 인터페이스 기반의 프록시가 생성된다


 DataSourceTransactionManager 클래스

 역할

  - JDBC 3.0을 통해 트랜잭션 지원
  - 특정 datasource 로 부터 현재 쓰레드까지 JDBC connection 을 바인딩 한다 

 주요 메서드

  - setDataSource, getDataSource

  - doBegin

  - doCommit

  - doRollback



 (4.3) @Transactional 어노테이션 설정


        - 인터페이스 정의, 인터페이스의 메서드, 클래스 정의, 클래스의 퍼블릭 메서드 앞에 @Transactional 어노테이션을 설정 할 수 있다.

        - 트랜잭션을 적용하려는 메서드 등에 설정. 특정 메서드에서만 트랜잭션을 사용하는 경우, 인터페이스 혹은 클래스 전체에 거는 것보다

          특정 메서드에만 걸어주는 것이 성능면에서 효율적이다.


/**

* 데이터 일괄 삭제 후 insert 서비스

* @param CommandMap commandMap, String jasonData

* @return Map<String, Object> resultMap

* @throws Exception

*/

@SuppressWarnings({ "unchecked", "rawtypes" })

@RequestMapping(value = "/ajaxUpdateList", method = RequestMethod.POST)

@Transactional

public @ResponseBody Map<String, Object> updateFpFunctionList(

@RequestParam(value = "rowList", required = true) String jasonData, CommandMap commandMap)

throws Exception {

...... 생략

        

// 기존 데이터 일괄 삭제

mapDao.delete("groupId.artifactId.sample_delete_all", commandMap.translateMap());

   

// 업데이트 데이터, 한 row 씩 INSERT 처리

for (Object object : array) {

mapDao.update("groupId.artifactId.sample_insert", (Map) object);

}

       ..... 

}

return resultMap;

}



 @Transactional 속성

 propagation

 

  

 isolation

 

 

 readOnly 

 boolean

 읽기/쓰기 트랜잭션? or 읽기 전용 트랜잭션?  

 성능을 최적화하기 위해 사용할 수도 있고 특정 트랜잭션 작업 안에서 쓰기 작업이 일어나는  것을 의도적으로 방지하기 위해 사용하기도 함. 

 timeout

 int 

 트랜잭션 타임 아웃

 정해진 시간 내에 메소드 수행이 완료되지 않을 경우 rollback함

 default 값: -1 ( = timeout 수행하지 않음)

 rollbackFor

 

 정의된 exception에 대해서는 rollback을 수행함 

 noRollbackFor

 

 정의된 exception에 대해서는 rollback을 수행하지 않음

( ** propagation 과 isolation 개념은 아직 정확히 이해가 안되어 작성하지 못했다.. 



 (4.4) Transaction 이 잘 걸렸나 테스트


       - 위와 같이 트랜잭션 설정을 해놓았으니, 이제 정말 잘 설정된 것이 맞는 지 테스트를 해 볼 차례다.

         테스트는 jUnit 테스트로 진행해보았다.

       

@WebAppConfiguration

@RunWith(SpringJUnit4ClassRunner.class)

@ActiveProfiles("dev")

@ContextConfiguration(locations={"classpath*:/spring/context-*.xml", "classpath*:/config/dispatcher-servlet.xml"})

public class TestTransaction {


    @Autowired

private TransactionTest TransactionTest;

    

    @Autowired

private GenericDao<Map<String, Object>> mapDao;

@SuppressWarnings({ "unchecked", "rawtypes" })

@Test

public void test() throws Exception {

Map map = new HashMap();

map.put("YEAR", "2017");

map.put("userId", "testID");

map.put("name", "tester");

//삭제 후 테스트

mapDao.delete("groupId.artifactId.sample_delete", map);

//중복키 INSERT 테스트

try{

TransactionTest.testDuplecateInsert(map); --> testDuplecateInsert 클래스에서는 같은 데이터(map)를 insert 시도

                                                                                        --> 예외 발생(SQLServerException)

}

catch(Exception e){

//예외 발생 시 INSERT 여부 파악

List<Map<String, Object>> list = mapDao.list("groupId.artifactId.sample_select", map);

if(list.size() == 0 ) {

   System.out.println( "rollback success!" );

}else{

   System.out.println( "rollback fail!" );

}

}

}


위의 class를 test 클래스로 만들고 공통모듈 'aop'쪽에 TestTransaction.java 라는 클래스를 만들어 실제 testDuplecateInsert 메서드를 수행했다.

위 클래스에서 마우스 우측 > run as > junit Test 를 클릭하면 junit test 가 수행된다. (junit 테스트 관련 정리는 다음 포스팅에~!!)


그, 결과 삭제 후 insert 도중 exception이 발생하여 예외가 발생하기전에 insert 수행 처리 되었던 row까지 전부 rollback 되었다. 

트랜잭션 rollback 성공!!


<-- 발생 Exception: SQLServerException -->

com.microsoft.sqlserver.jdbc.SQLServerException: PRIMARY KEY 제약 조건 'TB_SAMPLE'을(를) 위반했습니다. 개체 'dbo.TB_SAMPLE'에 중복 키를 삽입할 수 없습니다. 중복 키 값은 (2017, testID, tester)입니다.

at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:196)

at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1454)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:388)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:338)

at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4026)

at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1416)

at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:185)

at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:160)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.execute(SQLServerPreparedStatement.java:320)

at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)

at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)

at net.sf.log4jdbc.PreparedStatementSpy.execute(PreparedStatementSpy.java:418) 


     ....... 생략

 rollback success!



트랜잭션을 무작정 걸기 전에, 왜 트랜잭션을 쓰는지, 어디에 걸어야 성능측면에서 가장 효율적일지 등의 고민을 해야할 것 같다. 

설정 후 테스트도 충분히 해보고~!


__________________________________________________________________________________________________________________________________________________________

** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :) 

** 본 포스팅은 아래의 reference 들을 참고하여 내용을 덧붙인 글입니다. 혹시, 문제가 되는 경우 알려주시면 조치하도록 하겠습니다.

** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.


  - https://ko.wikipedia.org/wiki

  - https://spring.io/guides/gs/managing-transactions/

  - https://blog.outsider.ne.kr/869





'Spring' 카테고리의 다른 글

[에러] no matching editors or conversion strategy found  (0) 2017.04.20
(작성중) dispatcher-servlet.xml 설정  (0) 2017.04.16
spring - profile  (0) 2017.03.19
Spring - BeanNameViewResolver  (0) 2017.01.29

프로젝트 개발환경을 업데이트 하던 도중.. Spring 관련 설정 하나 바꾼 것이 에러를 발생시켜 2~3시간 동안 매달렸다. 

같이 일하시는 차장님이 도와주셔서 다행히 에러 원인을 찾았다 ㅜㅜ 차장님 아니었으면 해결 못했을 뻔....


이번 정리로, 또 한번 새겨야겠다 설정 바꿀때는 항상 신중하게!!!! 


우선, 새로운 프로젝트의 기존 개발환경은 Spring 3.1.1 버전이었다. 이를 사내 프레임워크에 맞게 현행화 하기 위하여

Spring 4.3.3 버전으로 업데이트 했다. 


1) 배경


   - 개발환경 Spring 3.1.1 --> 4.3.3 버전 업데이트 



2) 에러


   - 화면 이벤트 발생 시 해당 결과값을 받아오지 않음. 개발자 도구(F12)로 확인해도 에러 떨어지는 게 없고, 서버에도 에러 로그 남는게 없다..



3) 원인


   - 소스코드 체크아웃 받은 이후로 건드린 소스가 없어서 왜 내 로컬에서만 해당 에러가 발생할까 고민이 많았다. 나만 바꾼거 위주로 거슬러 올라가

     생각하다보니 spring 설정이 생각났다. ㅎㅎ


   - dispatcher-servlet.xml 파일 내 BeanNameViewResolver 설정을 제거한 것이 문제였다.


  [AS-IS]

   : BeanNameViewResolver 설정 제거

 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />

    <property name="prefix" value="/WEB-INF/jsp/" />

    <property name="suffix" value=".jsp" />

    <property name="order" value="1" />

  </bean>

  <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

    <property name="order" value="0" />

  </bean>


   - 해당 설정이 없으니, view 매핑이 제대로 이루어지지 않아 결과값을 뿌려줄 화면을 못찾았던 것.

   - 참고로, BeanNameViewResolver는 view 이름과 동일한 이름을 갖는 bean 객체를 view 객체로 사용한다. order도 0이여서      

     InternalResourceViewResolver 보다 먼저 찾았겠넹... ㅎㅎ



 4) 해결


     - BeanNameViewResolver 설정을 다시 원복한 후 view 맵핑이 정상적으로 처리되었다.

     - spring 4.x 에 와서 deprecated 된 애도 아닌데 내가 왜 이 설정을 제거했는지 모르겠다.............. ㅎㅎ;;

       하나 제거할때마다 신중하게 테스트해보고 커밋하기 ㅎㅎ 


 

 5) 참고자료

 

    [BeanNameViewResolever]

     - BeanNameViewResolver는 spring container에 bean으로 등록된 view 이름을 찾아 사용하는 resolver.

     - modelAndView를 반환할 때 viewName을 셋팅하여 리턴하면 해당 beanName을 가진 view를 찾는다. 

     - 커스텀 view 클래스를 view로 사용하는 경우 주로 사용한다.

     

   - 하나의 Dispatcher-Servlet은 다수의 viewResolver를 사용할 수 있다(order 옵션으로 먼저 사용할 resolver 지정하여 사용)

     우선순위(order)는 0 부터 0,1,2...의 형태로 부여되며, 우선순위가 높은 viewResolver가 null을 리턴하면, 그 다음 우선순위를 가진 viewResolver에게

     view가 요청된다.

   - 주의할 점은, InternalResourceViewResolver는 항상 우선순위 마지막에 놓도록 한다. InternalResourceViewResolver는 항상 view이름에 매핑되는 view        객체를 리턴하기 때문에(prefix, suffix 사용하여) null을 리턴하지 않는다.  InternalResourceViewResolver가 우선순위가 높을 경우 그보다 낮은 우선순위

     의 viewResolver들은 사용되지 않게 된다.



    [InternalResourceViewResolver]

     - Resource를 대상으로 view를 찾는데, 정적 자원 즉, webapp 아래 자원들을 반환값으로 찾게 된다. 컨트롤러가 지정한 view 이름으로부터 

       실제로 사용될 view를 선택한다.

     - 컨트롤러가 지정한 뷰 이름 앞뒤로 prefix 프로퍼티와 suffix 프로퍼티를 붙인 값이 실제로 사용될 자원의 경로가 된다.

 



__________________________________________________________________________________________________________________________________________________________

** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :) 

** 본 포스팅은 아래의 reference 들을 참고하여 내용을 덧붙인 글입니다. 혹시, 문제가 되는 경우 알려주시면 조치하도록 하겠습니다.

** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.


  - http://snoopy81.tistory.com/325

  - http://blog.naver.com/PostView.nhn?      

    blogId=chm8410&logNo=220375757503&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView


   

'Spring' 카테고리의 다른 글

[에러] no matching editors or conversion strategy found  (0) 2017.04.20
(작성중) dispatcher-servlet.xml 설정  (0) 2017.04.16
spring - profile  (0) 2017.03.19
[Spring] Transaction 관리  (0) 2017.03.12

프로젝트 내 개발 진행 중 발생한 에러인데 아직 명확한 해결책은 나지 않았지만 우선 정리해 둔다.


 @Autowired

  private GenericDao<Map<String, Object>> dao;

 @Autowired

  private SampleListDao<Map<String, Object>> sampleListDao;



우선 소스코드에 위와 같이 선언하여 service 구현체에 dao를 가져다 쓰려했다. 서버를 구동시키자 아래와 같은 에러가 떨어졌다.


1) 에러 메세지


Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [xxx.orm.mybatis.GenericDao] is defined: expected single matching bean but found 2: sampleListDao,genericDao

at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:172)



 - 확인해보니, 찾으려는 bean에대해 한 개 이상의 bean이 존재하여 발생하는 에러였다. 

 - 에러에 대해 알아보기 위해 GenericDao와 SampleListDao 소스에 각각 들어가 살펴보았다.

   GenericDao는 SqlSessionDaoSupport를 extends 한 class 였고, SampleListDao는 그 GenericDao를 extends하고 있는 class였다. (내가 그렇게 만듬...ㅎ)



2) 원인


 - @Autowired로 주입하고 있기 때문에 Type을 검색하여 연결하는데, SampleListDao와 GenericDao의 생성 type이 결국 조상 class인 

   SqlSessionDaoSupport로 type이 같기 때문에 @Autowired가 누굴 찾아 주입해야하는지 명확히 알 수 없기 때문이다.

   이러한 경우 name 을 주어 어떤 bean을 주입할 지 결정해주곤 한다.


- 그래서 아, name 으로 구분하면 되겠네 하고 name을 주어 @Resource로 빈 주입을 시도했다.

- 하지만 예상과 다르게 계속 같은 에러가 발생했다....충격 

  음 아직 명확한 답은 모르겠으나, 'extends' 가 문제인 것 같다. SampleListDao가  SqlSessionDaoSupport를 extends 하여 맨위와 같이 선언하면

  문제없이 돌아간다. (참고로 SqlSessionDaoSupport는 abstract class)


- SqlSessionDaoSupport를 extends 하면 name 기반으로도 주입이 잘 된다. 



3) 해결


    - 명확한 해결방법은 좀 더 연구해보아야 할 것 같다... 자료도 더 찾아보고

    

    

4) 보충 자료


먼저 @Autowired 와 @Resource.


@Autowired 와 @Resource는 모두 의존관계를 자동으로 주입하기 위한 설정이다. 

비슷한 기능을 하지만 약간의 차이가 존재하는데, 이 둘의 차이점은 아래와 같다.



 @Autowired

 @Resource

 공통점

 의존관계를 자동으로 주입하기 위한 설정

 차이점1: 지원

 Spring Framework

 Java

차이점2: 검색 

bean의 Type으로 검색하여 의존성 주입 

bean의 Name으로 검색하여 의존성 주입 

 옵션

 @Autowired는 타입을 이용해서 자동적으로 값을 설정하기때문에 해당 타입의 빈 객체가 존재하지 않거나 또는 2개이상 존재할 경우 빈객체를 생성할때 예외를 발생시킨다.이 경우를 대비하여  @Autowired(required=false) 옵션을 설정할 수 있다. 해당 옵션을 설정하면 연결할 bean을 찾지 못해도 예외를 발생시키지 않는다.

 name 속성을 이용하여 명시적으로 bean name을 줄 수 있다.

 단점

 type으로 검색하여 연결하기 때문에 같은 타입이 2개 이상 존재하는 경우, 예외가 발생한다.

  --> 보완: @Qualifier

        (동일한 type의 bean 객체들 중 name을 사용하여 특정 bean

        을 연결하도록 설정 가능)

 


 - @Autowired는 spring에서 제공하는 annotation이기 때문에 spring을 쓰지 않고 다른 framework를 쓰는 경우

   더이상 사용할 수 없다는 단점이 있다. 반면, @Resource는 JAVA에서 제공하는 annotation이기 때문에

   framework에 관계없이 계속 사용할 수 있다는 장점이 있다.


 - @Autowired는 생성 Type으로 연결하지만, @Resource는 name으로 연결하기 때문에 주입하려는 bean에 name을 설정해주어야 한다.

   예를 들면,

 

@Service("sampleService")

public class SampleServiceImpl implements SampleService { 


 ...


@Resource(name="sampleService")

private SampleService sampleService;


 - 위의 예제와 같이 주입하려는 bean (@Service)에 name(sampleService)을 설정해주고 해당 bean을 가져다 쓰려는 곳에서

  @Resource(name="sampleService") 로 검색하여 찾아 연결한다. 



 - @Qualifier는 @Autowired를 보완하기 위해 나온 annotation으로, 동일한 type의 빈 객체들 중 name을 기반으로 특정 빈을 사용할 수 있도록 

   설정해준다.


 @Autowired

 @Qualifier("genericDao")

 private GenericDao<Map<String, Object>> dao;

 @Autowired

 @Qualifier("sampleListDao")

 private SampleListDao<Map<String, Object>> sampleListDao;  




__________________________________________________________________________________________________________________________________________________________

** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :) 

** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.



+ Recent posts