'mybatis'에 해당되는 글 8건

  1. 2018.05.24 Oracle Clob 긴문자열 MERGE 할때 java.sql.SQLRecoverableException: IO Error: Connection reset 발생할때
  2. 2012.02.06 myBatis 동적쿼리에서 문자열 비교하기 2
  3. 2011.11.28 java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransactionFactory.newTransaction
  4. 2011.10.25 mybatis Oracle Procedure 호출하기
  5. 2011.10.18 mybatis 동적쿼리 조건문에 isEmpty, isNotEmpty 를 써보자. 2

Oracle Clob 긴문자열 MERGE 할때 java.sql.SQLRecoverableException: IO Error: Connection reset 발생할때



짧은 문자열은 말짱하게 잘되는데 긴문자열 입력할때 뜬금없이  java.sql.SQLRecoverableException 이 발생했다.


구글 찾아보니 random 어쩌고 하던데 그거 따라 해도 계속 에러났다.


결론는 MERGE 구문을 안쓰는 것이다 -.-


계속 찾아보면 방법이 나올것 같기도 하지만 경험상 몇번 검색해서 잘 안되면 방법이 없는 경우가 많아서 그냥 포기하기로...


Mybatis 의 choose - when - otherwise 를 요런식으로 써서 최대한 MERGE 랑 비슷하게 변경하기로 했다. 쫌 많이 불편하지만 에러가 나는것을 어떻게 하나.


    <insert id="save">
        <selectKey keyProperty="seq" resultType="Integer" order="AFTER">
            <choose>
                <when test="seq==null">
                    SELECT S_SEQ.CURRVAL FROM DUAL
                </when>
                <otherwise>
                    SELECT ${seq} FROM DUAL
                </otherwise>
            </choose>
        </selectKey>
        
        <choose>
            <when test="seq==null">
                INSERT INTO TB_TBL (
                          SEQ
                        , COL1
                        , COL2
                ) VALUES (
                      S_SEQ.NEXTVAL
                    , #{col1}
                    , #{col2}
                )
            </when>
            <otherwise>
                UPDATE TB_TBL SET
                      COL1= #{col1}
                    , COL2= #{col2}
                WHERE SEQ = #{seq}
            </otherwise>
        </choose>
    </insert>



myBatis 동적쿼리에서 문자열 비교하기

myBatis 로 개발하면서 그동안 직접쿼리를 만들일이 없어서( 디비쪽 작업하시는 분이 Stored Procedure 를 맹글어 줘서 그걸 myBatis 로 호출했었음 )

myBatis 동적쿼리를 쓸일이 없었는데

최근에 혼자 개발하는 후로젝트를 하나 할일이 있어서 직접 쿼리를 맨들어야만 했었다.



그러다 보니 그동안 별 관심없던 myBatis 동적쿼리를 써서 개발해야만 해서 문득 써 보았는데 삽질이 시작되었다.


myBatis 는 iBatis 에서 쓰던 <isEmpty/> <isEquals/> <isNotEquals/> 요딴 태그들 대신

간단명료하게 <if test="조건"/> 요걸로 바꼈다.

오홍 좋은데 하면서 개발을 하다

문자열을 비교해서 처리할 부분이 생겨서 내는 당연히 <if test="removed=='N'" > 요렇게 하면 될줄 알고 했는데 아무리 해도 안됐다.

<if test="removed==N" > 이런것도 해보고 오만걸 다써봤는데 계속 삽질만 됐다.



구글로 검색을 해도 키워드를 후진 키워드를 넣었나 검색도 드럭게 안됐다. ... -_-

겨우 해결방법을 찾았는데.. 음 이런걸 검색하는 능력이 후지진 않았는데 이상하게 검색이 잘 안됐다. 



결론적으로 죠걸 해결할려면 요렇게 하면 된다.
<if test="removed!=null and removed.equalsIgnoreCase('N')">REMOVED = 'N'</if>



보니까 죠기 test 에서 파라메터로 넘어온 프로퍼티 객체의 메소드를 직접 호출할수 있는것 같다!!!!!

test 안에서 쓰는 메소드니깐 return 이 boolean 타입이여야 하긋지???

파라메터로 null 이 넘어올수도 있으니깬 익셉션 나는걸 방지하기 위해서 일단 null 인지 비교하고 다음으로 넘어온 프로퍼티가 스트링 객체니까

대소문자 안가리고 비교하라고 equalsIgnoreCase 메소드를 호출하도록 했다. 물론 equals() 메소드를 호출해도 상관은 없다.

 

java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransactionFactory.newTransaction



아침에 출근 했는데 갑자기 온 사방에서 내가 만든 시스템에 로그인이 안된다고 쌩 앙탈들을 부렸다.


svn 자동으로 소스를 체크아웃 받아서 maven 으로 배포를 시켜주는 스크립트를 작성해서 매일 새벽 5시에 자동으로 배포 시키도록 해 놨는데.

어떤 아이가 잘못된 소스를 커밋해 놔서 그게 같이 배포가 된줄 알고 로그를 찬찬히 살펴봤더니 그런 종료의 에러가 아니였다.



익셉션 로그를 보니  첨보는 에러인 

java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransactionFactory.newTransaction(Ljava/sql/Connection;)Lorg/apache/ibatis/transaction/Transaction; 

요런 에러가 뽓 있었다.

대충 보니 mybatis 에서 나는 에러 같았다.




에러의 원인은 요랫다.

maven 디펜던시에 mybatis 최신 스냅샷 버전을 받도록 설정이 되 있어서, 최신 스냅샷 버전의 라이브러리로 바뀌는 바람에 나는 에러였다.

기존 mybatis 디펜던시 설정은 요랬다. 
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.1.0-SNAPSHOT</version>
</dependency>
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.0.3-SNAPSHOT</version>
</dependency>



요렇게 되 있는걸 릴리즈 버전을 쓰도록 요래 바꿔 주니깐 다시 잘 된다.
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.0.6</version>
</dependency>
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
	<version>1.0.2</version>
</dependency>



mybatis 는 살짝살짝 버그가 쫌 있어서 최신 버전을 쓰는게 좋다고 해서 그렇게 해 놨는데, 스냅샷 버전을 쓰는것은 지양해야 되겠다.

mybatis Oracle Procedure 호출하기


개인적으로 getter, setter 클래스를 만드는걸 싫어함으로 그냥 map, list 로 결과를 받는 예제를 맹글어 보겠다.

대충 요렇게 선언된 PROCEDURE_NAME 이라는 프로시져가 있다고 가정하면~
CREATE OR REPLACE PROCEDURE PROCEDURE_NAME
(
	c_resurt OUT P_OUT_CURSOR.CURSORTYPE,
	v_year  in   varchar2,
	v_term  in   varchar2,
	v_no    in   varchar2
)
AS ....

요 프로시져를 호출하는 mapper xml 파일은 요렇다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="test">
	<resultMap id="test" type="hashmap"></resultMap>
	
	<select id="test" statementType="CALLABLE">
		{ 
			CALL PROCEDURE_NAME(
				#{result, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=test},
				#{year},
				#{term},
				#{no}
			)
		}
	</select>
</mapper>

요기에서 보면 꼭 해줘야 될게

1. resultMap 을 hashmap 타입으로 하나 선언해 줘야 한다. (※ id 는 다른 xml 파일에 있는 resultMap id 와 중복되면 안된다.)

2. select 엘리먼트의 statementType 을 CALLABLE 로 설정해 줘야됨.

3. 프로시져 파라메터중 IN 타입은 잡다구리한거 설정할 필요가 없지만, OUT 타입은 위와 같이 선언해 주고 resultMap 에는 위에서 설정한 resultMap의 id를 적어줘야 한다.

요 세가지만 주의하면 mapper xml 작성은 끝~




다음으로 죠걸 호출하는 java 소스 부분이다. 편의상, 테스트 한다고 작성했던 Spring Controller 를 그대로 옮겨 적겠다. 다른데서 호출하는것도 호출방식은 다 똑같으니까 잘 땡겨다 쓸 수 있을것이라 생각한다.
package controller;

import java.util.HashMap;
import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Test {
	
	@Autowired SqlSessionTemplate oracle;
	
	@RequestMapping("/test")
	public void test(ModelMap model){
		// 파라메터 셋팅
		Map param = new HashMap();
		param.put("year", "2010");
		param.put("term", "xxx");
		param.put("no", "1234");
		
		// 프로시져 호출
		oracle.selectOne("test.test", param);

		// 결과보기
		System.out.println(param);
		
		// 파라메터로 넘겨준 HashMap 에 
		// mapper xml 에서 호출할때 선언했던 #{result, mode=OUT, ~~} 
		// 요부분의 result 라는 key로 결과를 담아준다.
		// #{output, mode=OUT, ~~} 이라고 했으면 param.get("output") 으로 받으면 된다.
		model.put("result", param.get("result"));
	}
}

대충보면 알겠지만 보통 쿼리인 경우는 selectOne() 메소드의 호출결과로 쿼리결과를 리턴받지만

프로시져에서 OUT 타입 변수로 결과를 리턴할 경우 selectOne() 의 결과로 아무것도 리턴되지 않는다.

대신 호출할때 넘겨준 파라메터에 결과를 담아서 넘겨준다 -_-;



그래서 리스트로 결과를 받기 위해서 굳이 selectList 로 호출을 안해도 되고 그냥 selectOne 만 쓰면된다.

쿼리 결과가 list 인 경우 위 예제같은 경우 result 에 ArrayList 안에 HashMap 들이 들어가 있는 형태로 결과를 넣어준다.





mybatis 동적쿼리 조건문에 isEmpty, isNotEmpty 를 써보자.

iBatis 에서 mybatis 로 바뀌면서 바뀐것들 중에 하나가 동적쿼리문에서 쓰는 태그들이다.

iBatis 에 있던 <isEqual/> <isNotEqual/> 요런 것들이

mybatis 에서는 <if test="xxx == 'a'"></if> <if test="xxx != 'a'"></if> 요렇게 대체할 수 있어서 쫌더 간결해 진것 같다.

그런데 test="" 요기에서 쓸수 있는 비교연산자들 중에는 null 인지 빈 공백인지 판단하던 <isEmpty/>, <isNotEmpty/> 를 대체할만한 비교연산자가 없었다.

null 인지 공백인지 mybatis 에서 판단하기 위해서는
<if test="xxx == null or xxx == ''"></if>

요렇게 쫏끔 번거롭게 쓸 수 밖에 없는것 같았다. 뭐 더 찾아보진 않았지만~



어째 다른 방법이 없나 쭉 찾아보니까~ 신기하게도 조건문에서 자바 클래스의 메소드를 호출해서 하는 방법이 있었다.

클래스를 하나 맨들고 거기에다 boolean 을 리턴해주는 static 메소드들을 뽓 맨들고 고것을 호출하는 방식이다.

내가 작성해본 클래스는 요렇다.
package stove99.tistory.com;

import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;

public class MyComparator {
	public static boolean isEmpty(Object obj){
		if( obj instanceof String ) return obj==null || "".equals(obj.toString().trim());
		else if( obj instanceof List ) return obj==null || ((List)obj).isEmpty();
		else if( obj instanceof Map ) return obj==null || ((Map)obj).isEmpty();
		else if( obj instanceof Object[] ) return obj==null || Array.getLength(obj)==0;
		else return obj==null;
	}
	
	public static boolean isNotEmpty(String s){
		return !isEmpty(s);
	}
}


죠렇게 맨든 클래스를 땡겨다 쓰는 mabatis sql xml 예제는 요렇다.
<select id="testSQL" parameterType="map" resultType="hashmap">
	SELECT * FROM TB_TEST
 	WHERE
 		1=1
 		<!-- @패키지.클래스명@호출할메소드(파라메터) -->
 		<if test="@stove99.tistory.com.MyComparator@isEmpty(keyword)">
 			AND KEYWORD = #{keyword}
 		</if>
</select>
@패키지명.클래스@메소드 요렇게 호출해야 되기 때문에 패키지나 클래스명은 간단하게 명명하면 좋을것 같다.

뭐 쓰고보니 더 복잡해진것 같기도 하고 -_-

 아무튼 딸랑 empty 체크하는 거에만 활용해서 그럴수도 있지만, 자바 메소드를 호출할수 있다는 것은 이것저것 활용할데가 많을것 같다. 
prev 1 2 next