|
SSISO Community검색 |
|
SSISO Community메뉴 |
|
SSISO Community카페 |
|
블로그 카테고리 |
|
|
Log4j로 검색한 결과 |
|
등록일:2008-06-09 13:29:41 작성자: 제목:JNDI Datasource HOW-TO 문서 ( 자카르타 서울 수리바다님 번역) |
|
JNDI Datasource HOW-TO
소개 Introduction |
JNDI Datasource 설정은 JNDI-Resources-HOWTO에 상세하게 나와있지만 tomcat-user 메일링리스트에서 보면 각각의 설정이 다소 까다롭다고 합니다.
많이 쓰이는 데이타베이스에 대하여 tomcat-user 메일링리스트에 올려진 몇개의 설정 예제가 여기 있습니다.
이들 간단한 메모들은 mysql 설정과 tomcat-user 메일링리스트의 피드백에서 나온 것임을 알아야 합니다. 상황에 따라 다릅니다. 만일 좀 더 많은 사람에게 도움이 될 만한 테스트해본 설정이 있거나 어쨌건 이 섹션에 좋은 내용이 될 만한 것이라면 알려주십시오. |
데이타베이스 커넥션풀(DBCP) 설정 Database Connection Pool (DBCP) Configurations |
DBCP는 JDBC 2.0을 지원합니다. JVM 1.4를 사용하는 시스템에서는 DBCP는 JDBC 3.0을 지원할 것입니다. JVM 1.4에서 DBCP와 JDBC 3.0의 특징을 사용해보았으면 알려주십시오.
설정매개변수 모두를 보려면 DBCP Javadocs에서 BasicDataSource 클래스를 보십시오.
설치 |
DBCP는 Jakarta-Commons 데이타베이스 커넥션 풀을 사용하는데 그것은 여러개의 Jakarta-Commons 컴포넌트들에 의존합니다.
- Jakarta-Commons DBCP 1.0
- Jakarta-Commons Collections 2.0
- Jakarta-Commons Pool 1.0
이 jar 파일들은 JDBC 드라이버 jar 파일과 함께 $CATALINA_HOME/common/lib 에 설치하여야 합니다.
주의:써드 파티 드라이버는 zip 파일이 아닌 jar 파일이어야 하며 Tomcat은 $CATALINA_HOME/common/lib/*.jar 만을 클래스패스에 추가합니다.
주의: 이 jar 파일들을 WEB-INF/lib , $JAVA_HOME/jre/lib/ext 나 다른 곳에 설치하지 마십시오. $CATALINA_HOME/common/lib 외에 다른 위치에 설치했을때 문제가 생길 수 있습니다.
|
데이타베이스 커넥션 풀이 새는 것을 막는 방법 |
데이타베이스 커넥션 풀은 데이타베스의 커넥션들의 풀을 만들고 관리합니다. 이미 있는 커넥션을 재생하여 재사용하는 것은 새 커넥션을 가져오는 것보다 효율적입니다.
커넥션 풀링에는 한가지 문제가 있습니다. 웹 애플리케이션은 명시적으로 ResultSet, Statement, Connection을 닫아야 합니다. 웹 애플리케이션에서 이들 자원들을 닫지 못하게 되면 다시 재사용할 수가 없으며 데이타베이스 커넥션 풀 "구멍"이 생깁니다. 이것은 결국 웹 애플리케이션에서 더 이상 쓸 수 있는 데이타베이스 커넥션이 없을 때 커넥션 에러를 내게 될 것입니다.
이에 대한 해결책이 있습니다. Jakarta-Commons DBCP는 이렇게 버려진 커넥션을 추척하고 복구하도록 설정할 수 있습니다. 복구할 뿐만 아니라 이들 자원들을 열고서는 닫지 않았던 코드를 찾아 추적 결과를 만들어내기도 합니다.
버려진 커넥션이 제거되고 재생되도록 DBCP DataSource를 설정하기 위해 DBCP DataSource Resource 의 ResourceParams 에 아래 매개변수를 추가하면 됩니다. :
사용할 수 있는 커넥션이 부족해진다면 DBCP는 버려진 커넥션을 찾아 복구하고 재생합니다. 디폴트는 false 로 되어 있습니다.
커넥션이 버려졌다고 간주되기 전에 사용되지 않은 시간(초)를 설정하기 위해 removeAbandonedTimeout 를 설정하십시오.
|
|
|
|
removeAbandonedTimeout
60
|
|
|
|
| 버려진 커넥션을 제거하는데 기본적으로 정해진 타임아웃 시간은 300초입니다.
만일 커넥션 자원을 낭비한 코드 위치의 로그를 남기려고 한다면 logAbandoned 패러미터를 true 로 할 수 있습니다.
기본은 false 로 되어 있습니다.
|
MySQL DBCP 사용예 |
0. 소개
MySQL과 mm.mysql JDBC 드라이버가 잘 연동된다고 보고된 버전은 다음과 같습니다.
- MySQL 3.23.47, MySQL 3.23.47 using InnoDB, MySQL 4.0.1alpha
- mm.mysql 2.0.14 (JDBC Driver)
새로 MySQL mm.mysql 3.0 driver를 테스트해봤다면 알려주시기 바랍니다.
1. MySQL 설정
달리하면 문제를 일으킬 수도 있으므로 이 지시를 반드시 따르십시오.
test 유저, 새 데이타베이스, 테스트 테이블 하나를 만드십시오. mySQL 유저는 할당된 패스워드가 있어야합니다. 비어있는 패스워드를 가지고서는 드라이버가 연결에 실패할 것입니다.
|
|
|
|
mysql> GRANT ALL PRIVILEGES ON *.* TO javauser@localhost
-> IDENTIFIED BY 'javadude' WITH GRANT OPTION;
mysql> create database javatest;
mysql> use javatest;
mysql> create table testdata (
-> id int not null auto_increment primary key,
-> foo varchar(25),
-> bar int);
|
|
|
|
|
주의: 위의 유저는 테스트가 끝나면 제거되어야 합니다.
다음으로 testdata 테이블에 테스트 데이타를 넣으십시오.
|
|
|
|
mysql> insert into testdata values(null, 'hello', 12345);
Query OK, 1 row affected (0.00 sec)
mysql> select * from testdata;
+----+-------+-------+
| ID | FOO | BAR |
+----+-------+-------+
| 1 | hello | 12345 |
+----+-------+-------+
1 row in set (0.00 sec)
mysql>
|
|
|
|
|
2. server.xml 설정
$CATALINA_HOME/conf/server.xml 에 리소스 선언을 추가하여 Tomcat에서의 JNDI 데이타소스를 설정하십시오.
이것을 examples 컨텍스트의 와 localhost 정의를 닫는 태그인 사이에 추가하십시오.
|
|
|
|
factory
org.apache.commons.dbcp.BasicDataSourceFactory
maxActive
100
maxIdle
30
maxWait
10000
username
javauser
password
javadude
driverClassName
org.gjt.mm.mysql.Driver
url
jdbc:mysql://localhost:3306/javatest?autoReconnect=true
|
|
|
|
|
3. web.xml 설정
이제 테스트 애플리케이션에 대한 WEB-INF/web.xml 을 만드십시오.
|
|
|
|
MySQL Test App
DB Connection
jdbc/TestDB
javax.sql.DataSource
Container
|
|
|
|
|
4. 테스트 코드
이제 이후에 사용할 간단한 test.jsp 파일을 만드십시오.
|
|
|
|
<%
foo.DBTest tst = new foo.DBTest();
tst.init();
%>
Results
Foo <%= tst.getFoo() %>
Bar <%= tst.getBar() %>
|
|
|
|
|
새로 만들어진 데이타소스와 커넥션풀을 실제로 사용할 자바 클래스를 만드십시오. 주의: 이 코드는 실무에서 쓰일 만한 코드는 아닙니다. 단지 테스트 목적으로만 사용되는 것입니다. :-)
|
|
|
|
package foo;
import javax.naming.*;
import javax.sql.*;
import java.sql.*;
public class DBTest {
String foo = "Not Connected";
int bar = -1;
public void init() {
try{
Context ctx = new InitialContext();
if(ctx == null )
throw new Exception("Boom - No Context");
DataSource ds =
(DataSource)ctx.lookup(
"java:comp/env/jdbc/TestDB");
if (ds != null) {
Connection conn = ds.getConnection();
if(conn != null) {
foo = "Got Connection "+conn.toString();
Statement stmt = conn.createStatement();
ResultSet rst =
stmt.executeQuery(
"select id, foo, bar from testdata");
if(rst.next()) {
foo=rst.getString(2);
bar=rst.getInt(3);
}
conn.close();
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
public String getFoo() { return foo; }
public int getBar() { return bar;}
}
|
|
|
|
|
마지막으로 웹 애플리케이션을 $CATALINA_HOME/webapps 에 DBTest.war 라는 이름의 war 파일이나 DBTest 라는 서브 디렉토리로 배치하십시오.
배치되고 나면 실제로 실행이 되는지 보기 위해 브라우저에서 http://localhost:8080/DBTest/test.jsp 를 열어보십시오. |
|
Tyrex 커넥션 풀 Tyrex Connection Pool |
소개 |
Tomcat 4.1은 Tyrex 1.0을 사용하여 트랜잭션 관리와 리소스 설정 지원 기능을 제공합니다. 이는 사용자가 표준 javax.transaction.UserTransaction 뿐 아니라 JNDI 네임스페이스로부터도 JTA/JCA 리소스를 얻을 수 있도록 합니다.. |
필요한 jar 설치 |
웹 애플리케이션이 Tyrex를 사용하도록 하기 위해서 webapp와 Tomcat은 Tyrex jar와 Tyrex jar가 필요로 하는 jar 파일들에 접근할 필요가 있습니다. 아래에 필요한 jar 파일들과 이를 구할 수 있는 곳의 리스트가 있습니다.
다음 jar 파일들은 http://tyrex.exolab.org에서 구할 수 있는 Tyrex 바이너리 배포판에 포함되어 있습니다.
- tyrex-1.0.jar
- ots-jts_1.0.jar
- jta_1.0.1.jar
- xerces-J_1.4.0.jar
다음 두 jar 파일도 역시 필요합니다.
이들 여섯 개의 jar 파일들은 Tomcat과 웹 애플리케이션에서 읽을 수 있도록 $TOMCAT_HOME/common/lib에 넣어야 합니다. |
톰캣 설정 |
Tyrex XML 설정파일을 만들었다면 JNDI 네임스페이스에 Tyrex 리소스를 등록하여야 합니다. 이것은 Tomcat의 server.xml 파일에서 하면 됩니다. 두가지 중요한 패러미터가 쓰여져야 하는데 도메인 설정 파일 이름(tyrexDomainConfig )과 사용될 Tyrex 도메인 이름(tyrexDomainName )입니다. 이는 다음과 같이 환경 매개변수로서 세팅하면 됩니다.
(웹 애플리케이션의 엘리먼트 아래에) 이제 리스소를 설정해야 합니다.
몇 가지 지적할 것이 있습니다.
- 리스소의 type은 Tyrex를 어떻게 설정하였는지와 상관없이
tyrex.resource.Resource 이어야 합니다.
- 오직 하나의 ResourceParam 패러미터
name (Tyrex 설정 파일에 쓰여진 리소스 이름)만이 필요합니다.
- Tomcat/JNDI 리소스와 Tyrex 리소스 간의 차이를 주목하십시오.(처음 보면 혼동이 될 것입니다.)
|
|
OCI 클라이언트로 Oracle8i 연결 Oracle 8i with OCI client |
소개 |
OCI 클라이언트를 사용하여 JNDI 데이타소스를 생성하는 것을 자세히 설명하지는 않으며 위의 Oracle and DBCP solution과 결합될 수 있는 부분입니다.
OCI 드라이버를 사용하기 위하여 먼저 오라클 클라이언트가 설치되어야 합니다. 씨디에서 Oracle8i(8.1.7)를 설치하고 otn.oracle.com에서 적당한 JDBC/OCI 드라이버(Oracle8i 8.1.7.1 JDBC/OCI Driver)를 다운로드하십시오..
Tomcat에서 사용하기 위해서 classes12.zip 를 classes12.jar 로 이름을 바꾼 다음에, $CATALINA_HOME/common/lib 에 복사를 하십시오. 사용하고 있는 Tomcat과 JDK 버전에 따라서는 javax.sql.* 클래스를 빼야 할 수도 있습니다. |
결합하기 Putting it all together |
$PATH 나 LD_LIBRARY_PATH 에 ocijdbc8.dll 나 .so 이 있는지($ORAHOME\bin 에 있는 파일) 확인하고 System.loadLibrary("ocijdbc8"); 를 사용하는 간단한 테스트 프로그램을 이용하여 네이티브 라이브러리가 로드되는지도 확인하십시오.
이제 다음 라인들을 포함한 간단한 테스트 서블릿이나 jsp를 작성하십시오.
|
|
|
|
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
conn =
DriverManager.getConnection("jdbc:oracle:oci8:@database","username","password");
|
|
|
|
|
먼저 UnsatisfiedLinkError 가 나오면 다음과 같은 문제가 있다는 것을 말합니다.
- JDBC 클래스 파일과 오라클 클라이언트 버전이 서로 맞지 않는 것입니다. 이는 필요한 라이브러리 파일을 찾을 수 없다는 얘기입니다. 예를 들어 8.1.5 오라클 클라이언트 버전을 가지고서 8.1.6 오라클 버전에 있는 classes12.zip을 사용하고 있을 수도 있는 것입니다. classesXXXs.zip 파일과 오라클 클라이언트 프로그램은 일치해야 합니다.
$PATH 와 LD_LIBRARY_PATH 문제
- otn에서 다운로드한 드라이버는 인식하지 않고
$ORAHOME\jdbc\lib 에 있는 classes12.zip 파일이 잘 작동한다고 알려지고 있습니다.
다음으로 ORA-06401 NETCMN: invalid driver designator 에러를 경험할 수도 있습니다.
오라클 문서에서는 "로그인(연결) 문자열이 유효하지 않은 드라이버를 지정해서 생기는 에러이며 문자열을 고쳐서 다시 연결을 시도하라"고 되어 있습니다. 데이타베이스 연결 문자열(host:port:SID 형태)을 다음과 같이 바꾸십시오. (description=(address=(host=myhost)(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))
TNS이름을 정리하는 것이 정말로 필요한 것 같지는 않습니다. 물론 저는 오라클 DBA가 아니기 때문에 확실한 것은 아닙니다.(역자주: 믿지는 마십시오.) | |
일반적으로 일어날 수 있는 문제 Common Problems |
데이타베이스를 사용하는 웹 애플리케이션에서 겪게되는 일반적인 문제와 이를 해결하는 방법에 대한 팁들을 이제 얘기하도록 하겠습니다.
가끔 데이타베이스 연결이 되지 않는 문제 Intermittent dB Connection Failures |
Tomcat은 JVM내에서 구동합니다. JVM은 주기적으로 더 이상 사용하지 않는 자바 객체를 제거하기 위해 가비지 컬렉션(GC)을 실행합니다. JVM이 Tomcat내 코드의 GC를 실행하면 Tomcat은 동작을 멈춥니다. 데이타베이스 연결 최대시간이 가비지 컬렉션 시간보다 작다면 데이타베이스 연결 에러를 보게 될 것입니다.
카비지 콜렉션이 얼마나 오래 걸리는지에 대한 데이타를 모으기 위해서는 Tomcat이 시작될 때 CATALINA_OPTS 에 -verbose:gc 변수를 추가하십시오. verbose gc 옵션이면 $CATALINA_BASE/logs/catalina.out 로그 파일이 가비지 컬렉션이 얼마나 걸리는지를 포함한 모든 데이타를 포함할 것입니다.
JVM이 99%로 잘 조정되었을 때 GC는 일초 이하가 걸릴 것입니다. 그 외에도 몇 초밖에 걸리지 않습니다. 아주 드물게 GC에 10초 이상 걸릴 수도 있습니다.
데이타베이스 연결 초과시간을 반드시 10초에서 15초 사이로 정하십시오. DBCP에서는 maxWait 매개변수를 사용하여 설정하십시오. |
임의 연결 닫힘 오류 Random Connection Closed Exceptions |
이것은 한 요청이 커넥션풀에서 디비 연결을 하나 가져와서 그것을 두번 닫으려고 할때 일어날 수 있습니다. 커넥션풀을 사용할 때는 연결을 닫으면 다른 요청에서 재사용하기 위해 풀로 돌아가는 것이지 커넥션을 닫는 것이 아닙니다. 그리고 Tomcat은 동시적인 요청들을 처리할 다중 스레드를 사용합니다. Tomcat에서 이런 에러가 일어날 수 있는 일련의 이벤트의 예가 있습니다. 쓰레드 1에서 실행되는 요청 1이 디비 연결을 얻습니다.
요청 1이 디비 연결을 닫습니다.
JVM이 쓰레드2로 실행 스레드를 전환합니다.
쓰레드 2에서 실행되는 요청 2가 디비 연결(요청 1이 막 반납한 같은 연결)을 얻습니다.
JVM은 실행 쓰레드를 스레드 1로 다시 전환합니다.
요청 1은 마지막에 디비 연결을 두 번 닫습니다.
JVM은 실행 쓰레드를 또 다시 쓰레드 2로 전환합니다.
쓰레드 2의 요청 2는 디비 연결을 사용하고자 하지만 요청 1이 이미 닫았기 때문에 실패하게 됩니다.
이제 커넥션 풀에서 얻은 디비 연결을 사용하는 적절한 코드 예를 보이겠습니다. Connection conn = null;
Statement stmt = null; // Or PreparedStatement if needed
ResultSet rs = null;
try {
conn = ... get connection from connection pool ...
stmt = conn.createStatement("select ...");
rs = stmt.executeQuery();
... iterate through the result set ...
rs.close();
rs = null;
stmt.close();
stmt = null;
conn.close(); // Return to connection pool
conn = null; // Make sure we don't close it twice
} catch (SQLException e) {
... deal with errors ...
} finally {
// Always make sure result sets and statements are closed,
// and the connection is returned to the pool
if (rs != null) {
try { rs.close(); } catch (SQLException e) { ; }
rs = null;
}
if (stmt != null) {
try { stmt.close(); } catch (SQLException e) { ; }
stmt = null;
}
if (conn != null) {
try { conn.close(); } catch (SQLException e) { ; }
conn = null;
}
}
| | |
|
|
|
|
|