propagation="REQUIRED" read-only="true"


Spring AOP Transaction 과 관련하여 와와 같이 설정 하였을 경우 해당 설정이 적용되는 트랜잭션의 경우 insert/update/delete가 일어난다면 ".. TransientDataAccessResourceException .. java.sql.SQLException: Connection is read-only. .." 와 같은 예외가 나면서 중지되어야 한다고 인터넷, 책 등등에 설명이 잘 되어있다.


하지만... 안됐다.. 개삽질 했다.. 몇시간을 삽질한지 모르겠다..

별 셈플링을 다 해봤다.. 안됐다..


그런데 DB가 MYSQL로 셈플링 한 프로젝트에서 동일하게 적용해보았으나 잘 되었다.


이것저것 찾아보니 DBMS Vendor따라서.. 안될 수도 있단다..



[참고] https://groups.google.com/forum/#!searchin/ksug/AOP$20트랜잭션$20설정에$20대해서../ksug/tVLRWx8R_B4/iCL_Cz6VWzMJ

  • 기본 Bean
      heaer, resultList 와 맵핑될 Bean Class가 업무별로 달라지므로 우선 HashMap에 담고, getter 에서 특정 Bean으로 컨버팅해준다.
  • 
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.commons.beanutils.BeanUtils;
    
    /**
     * DB 아니고 외부 인터페이스에서 받아온 정보
     * @auther ddakker 2013. 6. 12.
     */
    public class ExternalBean {
    
    	private String resultCode;
    	private String errMsg;
    
    	private Map header;
    	private List<Map> resultList;
    	public String getResultCode() {
    		return resultCode;
    	}
    	public void setResultCode(String resultCode) {
    		this.resultCode = resultCode;
    	}
    	public String getErrMsg() {
    		return errMsg;
    	}
    	public void setErrMsg(String errMsg) {
    		this.errMsg = errMsg;
    	}
    	public Map getHeader() {
    		return header;
    	}
    	public void setHeader(Map header) {
    		this.header = header;
    	}
    	public List<Map> getResultList() {
    		return resultList;
    	}
    	public void setResultList(List<Map> resultList) {
    		this.resultList = resultList;
    	}
    
    	/**
    	 * 헤더 정보를 특정 Bean에 담아 리턴한다.
    	 * @param clz
    	 * @return
    	 * @auther ddakker 2013. 6. 14.
    	 */
    	public <T> T getHeader(Class<T> clz) {
    		Object objBean = null;
    		try{
    			objBean = clz.newInstance();
    			BeanUtils.copyProperties(objBean, header);
    
    			return (T) objBean;
    		}catch(Exception e){
    			throw ExceptionManager.createException("JSON 데이터를 Bean으로 맵핑[Header]하는 도중 에러가 발생하였습니다." + e);
    		}
    	}
    
    	/**
    	 * 배열 정보를 특정 List<Bean>에 담아 리턴한다.
    	 * @param clz
    	 * @return
    	 * @auther ddakker 2013. 6. 14.
    	 */
    	public <T> List<T> getResultList(Class<T> clz) {
    		List<T> list = new ArrayList<T>();
    		try{
    			Object objBean;
    			for( Map map : resultList ){
    				objBean = clz.newInstance();
    				BeanUtils.copyProperties(objBean, map);
    
    				list.add((T) objBean);
    			}
    		}catch(Exception e){
    			throw ExceptionManager.createException("JSON 데이터를 Bean으로 맵핑[ResultList]하는 도중 에러가 발생하였습니다." + e);
    		}
    		return list;
    	}
    }
    

  • 헤더 Bean
      각 업무에 맞는 Bean을 생성한다.
  • public class UserHeaderBean {
    	private String userNm;
    
    	public String getUserNm() {
    		return userNm;
    	}
    
    	public void setUserNm(String userNm) {
    		this.userNm = userNm;
    	}
    }
    

  • 배열 Bean
      각 업무에 맞는 Bean을 생성한다.
  • public class ListBean {
    	private String dlvrAddr1;
    	
    	public String getDlvrAddr1() {
    		return dlvrAddr1;
    	}
    }
    

    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import net.sf.json.JSONObject;
    
    public class TestCase {
            @Test
    	public void jsonTestCase() {
    		String jsonStr = "{'resultCode':'success', 'errorMsg': '','header':{'userNm':'ddakker'},'resultList':[{'dlvrAddr1': '서울~'},{'dlvrAddr1': '충남~'}]}";
    		
    		Map classMap = new HashMap();
    		classMap.put("header", HashMap.class);
    		classMap.put("resultList", HashMap.class);
    
    		JSONObject json = JSONObject.fromObject(jsonStr);
    
    		ExternalBean exBean = (ExternalBean) JSONObject.toBean(json, ExternalBean.class, classMap);
    		
    		if( exBean.getResultCode().equals("success") ){
    			UserHeaderBean hBean = exBean.getHeader(UserHeaderBean.class);
    			System.out.println(hBean.geUserNm());
    								
    			List<ListBean> lBeanList = exBean.getResultList(ListBean.class);
    			System.out.println(lBeanList.size());
    			System.out.println(lBeanList.get(0).getDlvrAddr1());
    		}
    	}
    }
    
    • json-lib-2.4-jdk15.jar
    • ezmorph-1.0.6.jar
    • commons-lang-2.6.jar
    • commons-logging-1.1.3.jar
    • commons-collections-3.2.1.jar
    • commons-beanutils-1.8.3.jar
    테스트 셈플 페이지 만들다가 Button 테그를 사용했더니, IE10에서 이상한 문제가 발생했다..
    한참 삽질 끝네.. 아래와 같이 하니 해결이 되네..
    예전에 IE6 특정 케이스에서 return false; 안 붙이면 클릭이 안되는 문제가 있더니만.. 또 삽질 무진장 했네..
    웬만하면 INPUT 테그를 사용해야겠다!!!

    
    


    import org.apache.commons.beanutils.BeanUtils;
    ..
    ..
    
    	public <T> T setParamegerBean(Class<T> clz) throws InstantiationException, IllegalAccessException, InvocationTargetException{
    		T t = clz.newInstance();
    		BeanUtils.copyProperties(t, ServletActionContext.getRequest().getParameterMap());
    		return t;
    	}
    
    import java.lang.reflect.Field;
    import org.apache.commons.beanutils.BeanUtils;
    ..
    ..
    
    public String intercept(ActionInvocation invocation) throws Exception {
        	log.info("---------- 파라미터 Bean에 셋팅 ----------");
    
        	Object action = invocation.getAction();
    
        	Field fs [] = action.getClass().getDeclaredFields();
        	for( Field f : fs ){
        		if( f.getName().indexOf("Bean") > 0 ){
        			String s [] = StringUtils.split(f.toString(), " ");
        			if( s.length == 3 ){
    	    			Class cls = Class.forName(s[1]);
    	    			Object obj = cls.newInstance();
    	    			BeanUtils.copyProperties(obj, ServletActionContext.getRequest().getParameterMap());
    	    	    	f.setAccessible(true);
    	    	    	f.set(action, obj);
        			}
        		}
        	}
        	return invocation.invoke();
        }
    

    우선 Spring AOP 에서 Proxy 를 사용하는데 두가지가 존재한다고 하네...

    1. JDK Dynamix Proxy    - Interface 가 존재해야 하고(Runtime 시점에 감싸주는거던데... 고로 야야야야야약간의 성능저하.??)
    2. CGLib Proxy             - 구현체만 있으면 됨..(Compile 시점에 감싸므로 성능저하 최소화)


    2번 방법으로 사용하려면 <aop:config proxy-target-class="true"> 셋팅이 필요함


    ex) 근데 Service Layer에서는 셋팅하지 않아도 정상적이였는데, Dao Layer에서는 문제가 생겼다.. 머징;;


    역시 지식이 너무 얕다.. ;; 

    삽질 무진장 했네


    [참고] https://groups.google.com/forum/?hl=ko&fromgroups=#!topic/ksug/pm2ET851V6U



    	
    	
    	
    
    	
    
    		
    			
    			
    			
    			
    			
    			
    		
    		
    
    	
    


    • *-servlet.xml 과 applicationContext.xml 설정 시 주의 점
      1. *-servlet.xml 에서 Controller Annotation 스캔 시 무조껀 Controller 만 함
      2. applicationContext.xml 에서는 Controller 를 제외 하고 스캔함
    • 위와 같이 하지 않을경우 둘의 상-하 상속관계에 따라서 applicationContext.xml 의 Bean이 사용되어지는것이 아니라 *-servlet.xml 의 Bean이 사용되어 진다고 함...
      그러므로 applicationContext.xml 에서 tx(Transaction)관련 설정을 해 놓아도 먹히지 않는 문제가 발생합니다.

    [*-servlet.xml]

    	
    		
    	
    
    [applicationContext.xml]


    	
    		
    	
    

    import java.io.FileOutputStream;
    import java.io.StringReader;
    
    import org.junit.Test;
    
    import com.itextpdf.text.Document;
    import com.itextpdf.text.Element;
    import com.itextpdf.text.FontFactory;
    import com.itextpdf.text.html.simpleparser.HTMLWorker;
    import com.itextpdf.text.html.simpleparser.StyleSheet;
    import com.itextpdf.text.pdf.PdfWriter;
    
    
    public class TestCreatePDF {
    
    	@Test
    	public void htmlCreate() throws Exception {
    		// TODO Auto-generated method stub
    		String fontname = "d:\\GulimChe.ttf";
    		String filename = "d:\\filename.pdf";
    		
    		FontFactory.register(fontname);
    		StringBuffer sBuff = new StringBuffer("<html>");
    		sBuff.append("<head></head>");
    		sBuff.append("<body>");
    		sBuff.append("<table border=1>");
    		sBuff.append("<tr><td>Test worker <b>한글</b> 테스트</td><td>11<b>1</b>11</td></tr>");
    		sBuff.append("</table>");
    		sBuff.append("</body>");
    		sBuff.append("</html>");
    		StringReader stringReader = new StringReader(sBuff.toString());
    
    		Document document = new Document();
    		StyleSheet st = new StyleSheet();
    		st.loadTagStyle("body", "face", "굴림체"); 
    		st.loadTagStyle("body", "encoding", "Identity-H"); 
    		st.loadTagStyle("body", "leading", "12,0"); 
    		HTMLWorker worker = new HTMLWorker(document);
    		PdfWriter.getInstance(document, new FileOutputStream(filename));
    		document.open();
    		java.util.List<Element> p = HTMLWorker.parseToList(stringReader, st);
    		for (int k = 0; k < p.size(); ++k)
    		    document.add((Element)p.get(k));
    		document.close();
    	}
    
    }

    GulimChe.ttf

    itextpdf-5.4.0.jar


    [출처] http://blog.wooriaru.com/131163646


    Tomcat 7.x + Jenkins ver. 1.500


    [Maven tomcat plugin을 이용하여 deploy -> reload 방법]

    tomcat/conf/tomcat-users.xml

    
    
    
    
    
    


    pom.xml

    
    	org.codehaus.mojo
    	tomcat-maven-plugin
    	1.1
    	
    		UTF-8
    		war
    		http://localhost/manager/text
    		
    		admin
    		admin
    	
    
    



    젠킨스 프로젝트 설정 Build 부분 명령어에 tomcat:redeploy tomcat:reload


    [Shell 실행하여 Tomcat 재시작 방법]


    jenkins에서 빌드 스크립트 종료 후 아래 shell 실행하면 정상 start 후 Process를 종료해버려서 기껏 올라간 Tomcat이 종료되는 문제가 발생한다.

    그럴 경우 해당 프로젝트 설정에서 "This build is parameterized" 체크 하고, "Add Parameter" 에서 BUILD_ID 에다가 아무 값이나 셋팅!!

    #!/bin/bash

    echo "Shutdown tomcat now...."
    bash /usr/local/tomcat/bin/shutdown.sh
    echo "tomcat is now terminated..."
    sleep 10
    if [ -z "`ps -eaf | grep java | grep /usr/local/tomcat/bin`" ]; then
            echo "Tomcat was terminated successfully."
    else
            ps -eaf | grep java | grep /usr/local/tomcat/bin | awk '{print $2}' |
            while read PID
                    do
                    echo "Killing $PID... "
                    kill -9 $PID
                    echo "Tomcat is being shutdowned"
                    done
    fi
    
    echo "tomcat restart now"
    /usr/local/tomcat/bin/./startup.sh
    AA=`ps -eaf | grep java | grep /usr/local/tomcat/bin`
    echo "AA: $AA"
    if [ -z "`ps -eaf | grep java | grep /usr/local/tomcat/bin`" ]; then
            echo "Error!!! Cannot start tomcat server."
    else
            echo "Tomcat restart succcessfully. "
    fi
    echo "Job finished"
    

    [참조 shell] http://ausgang.egloos.com/2947190

    startup.sh

    #!/bin/sh
    
    
    . ./env.sh
    
    export CATALINA_HOME=/usr/local/tomcat/apache-tomcat-8.0.9
    export CATALINA_BASE=/usr/local/tomcat/domains/$PROJECT_NM
    export JAVA_OPTS="-Djava.awt.headless=true -server -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+DisableExplicitGC"
    export CATALINA_OPTS=$CATALINA_OPTS" -Dfile.encoding=UTF-8"
    
    cd $CATALINA_HOME/bin
    
    ./startup.sh
    
    
    AA=`ps -eaf | grep java | grep $WAS_PATH`
    echo "AA: $AA"
    if [ -z "`ps -eaf | grep java | grep $WAS_PATH`" ]; then
            echo "Error!!! Cannot start tomcat server."
    fi
    
    while [ `netstat -an | grep :$WAS_PORT | grep LISTEN | wc | awk '{print $1}'` != 1 ]; do
            echo -ne "."
            sleep 1
    done
    
    echo "Check WAS Context Ready http://localhost:$WAS_PORT ..."
    
    until [ "`curl --silent --show-error --connect-timeout 1 -I http://localhost:$WAS_PORT | grep 'Coyote'`" != "" ];
    do
            echo -ne "."
            sleep 1
    done
    
    echo "Start WAS And Context $PROJECT_NM Tomcat Succcess"
    
    

    shutdown.sh

    #!/bin/sh
    
    
    . ./env.sh
    
    export CATALINA_HOME=/usr/local/tomcat/apache-tomcat-8.0.9
    export CATALINA_BASE=/usr/local/tomcat/domains/$PROJECT_NM
    
    $CATALINA_HOME/bin/./shutdown.sh
    
    I=0
    
    until [ "`ps -eaf | grep java | grep $WAS_PATH`" == "" ];
    do
            if [ $I == 5 ]; then
    		ps -ef | grep java | grep "$WAS_PATH " | awk {'print "kill -9 " $2'} | sh -x
                    break;
            fi
    
            let I=$I+1
    
            echo Stop WAS Finish? Sleeping for 2 seconds
            sleep 2
    done
    
    
    
    	Order deny,allow
    	Deny from all
    	Allow from 1.1.1.  # 1~255 활성
    
    

    + Recent posts