'oracle'에 해당되는 글 5건

  1. 2014.04.11 Oracle Client 다운로드 받기
  2. 2011.10.25 mybatis Oracle Procedure 호출하기
  3. 2011.08.23 Oracle 두 Date Type 컬럼 시간차 구하기 2
  4. 2011.08.22 Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션
  5. 2011.08.22 mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX

Oracle Client 다운로드 받기


토드는 다 좋은데 오라클 클라이언트가 설치되 있어야 디비에 접속을 할 수 있다는 살짝 후진점이 있다.


클라이언트 없어도 토드로 접속하는 방법을 찾아보는게 귀찮을까? 오라클 클라이언트를 설치하는게 귀찮을까?



쪼금 찾아보다 그냥 오라클 클라이언트를 설치하기로 했다.


근데 막상 클라이언트를 다운로드 받을려니 오라클 사이트에서 너무 꽁꽁 숨겨놓았는지 드럭게 찾기 힘들었다.



다운로드 받으러 고고씽

http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html



요기서 자신이 원하는 OS 버전옆의 See All 을 클릭해야 클라이언트를 다운받을 수 있는 페이지가 나타난다.

Oracle 12c 클라이언트 받을 사람들은 위쪽에 있는 See All 클릭하면 되겠다.





요기서 다운


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 들이 들어가 있는 형태로 결과를 넣어준다.





Oracle 두 Date Type 컬럼 시간차 구하기


여기서 start_date, end_date 컬럼의 데이터 타입은 DATE 임~
-- 두 날짜 사이가 몇 초 차이나는가?
SELECT ROUND((end_date-start_date)*24*60*60) FROM tb_name;


-- 두 날짜 사이의 몇 분 차이나는가?
SELECT ROUND((end_date-start_date)*24*60) FROM tb_name;


-- 두 날짜 사이의 몇 시간 차이나는가?
SELECT ROUND((end_date-start_date)*24) FROM tb_name;

Oracle JDBC : "스트림이 이미 종료되었습니다" 혹은 "java.sql.SQLException: Stream has already been closed" 익셉션

Oracle JDBC 로 CLOB 나 LONG 같은, 값을 Stream 형태로 읽어야 하는 타입들을 Select 할때 발생하는 Exception 이다.

나같은 경우는 mybatis로 select 할때 쿼리문과 쿼리결과를 Log4j 로그로 찍었는데 시쭈구리하게도  logger 에서 ResultSet을 로그로 찍었기 때문에 나는 에러였다.

찍혀 있는 로그를 가만히 살펴보면 쿼리문이랑 ResultSet 결과가 먼저 쭉 찍힌뒤 그 뒤로 익셉션이 쭉 발생하고 있었다.
고말인 즉슨, 로거에서 찍을때는 정상적으로 값을 가져왔다는 말이된다.



가만 입다물고 생각해보면, 로거에서 ResultSet을 찍을려고 값을 가져오면서 Stream이 닫혀 버렸기 때문에 나는 에러 같았다.

기존 log4j.xml 설정은
<logger name="java.sql">
	<level value="debug" />
</logger>
 요렇게 되 있어서 java.sql 패키지에 포함된 모든클래스에서 발생하는 로그들을 다 찍게 되 있었다.




고것을
<logger name="java.sql.Connection">
	<level value="debug" />
</logger>

<logger name="java.sql.PreparedStatement">
	<level value="debug" />
</logger>
요래 바꿔서 ResultSet 에 대한 로그를 안찍게 바꾸니 해결되었다. 로그가 아예 필요없다면 다 지워도 되고~
나는 어떤 쿼리가 실행됬는가 까지는 꼭 알고 싶어서..



이것도 왠지 버그인것 같은 느낌이 문득 들지만 언젠가는 해결될것이라고 믿는다. 아니면 내가 잘못 쓰고 있는건가???? 

테스트 라이브러리 버전
mybatis :  3.0.6-SNAPSHOT.jar
oracle jdbc driver : ojdbc6.jar (11.2.0.2.0) 

mybatis 에서 Oracle LONG, CLOB Select 시 에러날때 : getCLOB not implemented for class oracle.jdbc.driver.XXX

MySQL 에서는 어떤지 잘 모르겠지만 아무튼 오라클에서는 Long Type이나 CLOB Type 컬럼을 select 할때 getCLOB() 가 구현되지 않았다면서 에러가 난다.

mybatis 에서 패치를 해줘야 되나 오라클에서 패치를 해 줘야 하나 쫌 거시기 하지만 아무튼 지금! 현재는 Long 을 가져오질 못한다 -_-

누군가는 패치를 해주긋지~

현재 라이브러리 버전은 요렇다.!
mybatis :  3.0.6-SNAPSHOT.jar
oracle jdbc driver : ojdbc6.jar (11.2.0.2.0)

지금 당장 하기는 해야 겠고 고쳐줄때 까지 기다릴수 없으니 해결하기 위해선 mybatis config 파일에서 LONG TYPE에 대해 TypeHandler 를 설정해 주면 된다.

mybatis config 파일
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeHandlers>
		<typeHandler handler="stove99.handler.CLOBHandler" javaType="String" jdbcType="LONGVARCHAR"/>
	</typeHandlers>
</configuration>
설정을 보면 대략 알겠지만 LONG 타입을 뜻하는 LONGVARCHAR jdbcType 에 대하여 처리할 핸들러를 설정해 주는 것이다.





TypeHandler 는 org.apache.ibatis.type.TypeHandler 인터페이스를 implements 해서 간단하게 메소드 3개를 구현하면 된다.
stove99.handler.CLOBHandler 의 소스는 다음과 같다.
package stove99.handler;

import java.io.StringReader;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

public class CLOBHandler implements TypeHandler{

	@Override
	// 파라메터 셋팅할때
	public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) 
           throws SQLException {
		String s = (String) parameter;
		StringReader reader = new StringReader(s);
		ps.setCharacterStream(i, reader, s.length());
	}

	@Override
	// Statement 로 SQL 호출해서 ResultSet 으로 컬럼값을 읽어올때
	public Object getResult(ResultSet rs, String columnName) throws SQLException {
		return rs.getString(columnName);
	}

	@Override
	// CallableStatement 로 SQL 호출해서 컬럼값 읽어올때
	public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
		return cs.getString(columnIndex);
	}
}

내 나름대로 이해하고 있는걸 적어놓은 것이니 미심쩍다는 사람들은 첨부파일 pdf 에서 14쪽을 참고하셈~

MyBatis-3.0.3-User-Guide.pdf

 
prev 1 next