삶 가운데 남긴 기록 AACII.TISTORY.COM
JDBC 프로그래밍 본문
서버 설치 및 세팅
RSA 공개키/개인키로 Putty를 이용한 SSH 접속
Oracle 설치 및 연결
JDBC 드라이버
JDBC 드라이버 파일을 자바 프로그램에서 사용할 수 있도록 준비해놓아야 합니다.
이 JDBC 드라이버 파일은 오라클 설치경로의 ..\server\jdbc\lib 에서 jar 파일을 복사를하거나 오라클 사이트에서 다운받을 수 있습니다.
https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html
이제 준비된 JDBC 드라이버 파일을 웹 어플리케이션에서 자동으로 인식하도록 복사해야 합니다.
WAS가 설치된 HOME 경로 밑의 lib 폴더 혹은 웹 어플리케이션의 /WEB-INF/lib 폴더에 JDBC 드라이버 파일을 복사합니다.
오라클이 11g 가 설치 되어 있다면 아래 게시글을 참고 하셔도 좋습니다.
자바 웹 어플리케이션에서 데이터베이스에 sql 문을 실행하는 과정을 설명합니다.
여기서는 jdbc7.jar 파일을 /WEB-INF/lib 폴더에 복사한 후 진행했습니다.
그리고 DB서버는 vmware 를 이용해 리눅스를 설치하고 리눅스에 오라클DB를 설치하였으며 IP는 192.168.1.6 포트는 1521 인스턴스는 orcl 으로 세팅되어 있습니다.
자세한 서버 세팅 방법은 이 블로그의 다른 게시글 LINUX, DATABASE 카테고리를 참고해주세요.
1. JDBC 드라이버 로딩
Class.forName("oracle.jdbc.driver.OracleDriver);
2. DBMS 서버와 연결
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","scott","tiger")
여기서 jdbc:oracle:thin은 오라클 프로토콜을 의미합니다.
@localhost는 서버 아이피(호스트) 주소를 의미합니다.
1521은 오라클 DBMS의 서비스 포트를 의미합니다.
xe는 오라클 DBMS가 설치될 때 설정한 인스턴스(DB 이름)를 뜻합니다.
scott 은 DBMS사용자 계정 ID 이며 학습용 계정인 scott 이 기본적으로 생성되어 있습니다.
tiger는 scott 계정에 기본적으로 할당된 패스워드 입니다.
3. Statement | PreparedStatement 객체 생성
Statement stmt = conn.createStatement();
Statement 는 실제 프로젝트에서는 여러가지(성능,보안) 문제로 사용하지 않습니다.
대신 PreparedStatement 객체를 사용해 SQL 문을 ? 기호로 동적으로 생성할 수 있습니다.
PreparedStatement pstmt = conn.prepareStatement("insert into test values(?,?)");
pstmt.setString(1, id);
pstmt.setString(2, pwd);
여기서 pstmt.setString() 에 있는 숫자는 위 insert쿼리의 ? 기호에 매칭됩니다.
순서대로 1,2,3,4 ... 인덱스를 지정해 쿼리를 동적으로 생성할 수 있습니다.
4. SQL문 실행
ResultSet executeQuery(String sql) : select 쿼리를 실행하는 메소드 입니다. 결과 값은 ResultSet 타입으로 리턴합니다. cursor를 통해서 ResultSet 데이터의 내부적인 위치를 지정합니다.
int executeUpdate(String sql) : update나 delete, insert 하는 쿼리를 실행하는 메소드 입니다. int 값을 리턴합니다.
5. 자원 해제
DB작업을 하고 자원을 해제해주어야 하는 객체들은 아래와 같습니다.
ResultSet 객체: rs.close()
Statement 혹은 PreparedStatement 객체: stmt.close() 혹은 pstmt.close()
Connection 객체: conn.close()
실습
jdbc.jsp 파일을 생성합니다.
여기서는 192.168.1.6 서버 1521포트에 설치된 orcl 인스턴스에 계정 aacii 가 있다고 가정합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.sql.*" %>
<%
//JDBC 드라이버 로딩
Class.forName("oracle.jdbc.driver.OracleDriver");
//DB서버 접속
String url = "jdbc:oracle:thin:@192.168.1.6:1521:orcl";
Connection conn = DriverManager.getConnection(url, "aacii", "aacii");
//request 로부터 값을 획득
String sabun = request.getParameter("sabun");
String name = request.getParameter("name");
//PreparedStatement 객체 생성
PreparedStatement pstmt = conn.prepareStatement("insert into TABLE_1(sabun, name) values(?,?)");
pstmt.setString(1,sabun);
pstmt.setString(2,name);
//쿼리 실행
pstmt.executeUpdate();
//Statement 객체 생성
Statement stmt = conn.createStatement();
//SQL실행
//참고: 해당 데이터베이스와 테이블에는 미리 예제용 데이터들이 들어가 있습니다.
ResultSet rs = stmt.executeQuery("select * from TABLE_1");
while(rs.next()){
out.print("<br>"+rs.getString("sabun")+" : "+rs.getString("name"));
}
//자원 해제
rs.close();
stmt.close();
conn.close();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
테스트로 request 에 sabun을 1234, name을 tester 라고 주고 테스트 했습니다.
DataSource
사실 실제 프로젝트에서는 JDBC 방식으로 어플리케이션을 개발하지 않습니다.
속도도 느릴 뿐더러 SQL Injection 등 보안에도 취약하기 때문입니다.
가장 큰 문제는 요청이 있을 때마다 새로운 커넥션을 맺어야 한다는 것이 서버에 큰 낭비이자 부담입니다.
그래서 스레드에서 스레드 풀을 사용했던것 처럼 커넥션에도 커넥션 풀을 사용해서 관리합니다.
커넥션 풀(connection pool)은 미리 커넥션 객체를 생성해놓고 준비해 두었다가 필요할 때 가져다 사용하고 다 사용하면 객체를 풀에 반납하는 방식을 말합니다.
DataSource 객체는 커넥션 풀을 관리하기 위한 객체입니다.
이 DataSource 객체를 통해 Connection을 얻어오고 pool에 반납하는 작업 등을 수행할 수 있습니다.
DataSource를 이용하려면 다음과 같은 절차를 거쳐야 합니다.
- JNDI 서버에서 lookup() 메소드를 통해 DataSource 객체를 획득.
- DataSource 객체의 getConnection() 메소드를 통해 pool에서 free 상태의 Connection을 획득.
- Connection 객체를 통한 DB작업을 수행.
- DataSource 객체를 통해 Connection을 pool에 반납.
JNDI (JAVA Naming and Directory Interface)
어플리케이션에서 네이밍 & 디렉터리 서비스를 사용하게 해줍니다.
네트워크로 분산된 환경에서 필요한 자원을 획득하고 사용하기 위해 제공되는 Naming and Directory 서비스입니다.
실제 자원을 서비스 한다는 의미가 아니라 실제 자원을 Naming & Directory 서버에 등록하면 해당 자원을 사용하고자 하는 어플리케이션에서 Naming&Directory 서버에 접근하여 자원을 연결하여 이용할 수 있게 합니다.
흔히 DNS 서버가 이런 기능을 해줍니다.
server.xml 커넥션 풀 설정
server.xml은 WAS가 설치된 경로에 /conf/server.xml 이 있습니다.
이클립스의 경우에 톰캣이 설치되어 있다면 Servers 경로 아래 Tomcat경로에 가보면 server.xml이 있습니다.
server.xml에 <GlobalNamingResources> 태그가 있는데 다음과 같이 설정합니다.
<GlobalNamingResources>
<!-- 생략 -->
<!-- 오라클 서버 커넥션 풀 -->
<Resource driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.1.6:1521:orcl"
username="aacii"
password="aacii"
name="jdbc/myoracle"
type="javax.sql.DataSource"
maxActive="4"
maxIdle="2"
maxWait="5000" />
</GlobalNamingResources>
- dirverClassName: Class.forName() 에 인자로 지정하는 값
- url: 접속할 DB서버의 url, 포트번호, 인스턴스
- username: DB서버에 로그인 할 계정
- password: 로그인 할 계정의 비밀번호
- name: 현재 리소스를 등록할 이름 지정
- type: 현재 리소스의 타입을 지정(connection pool을 사용할 수 있는 DataSource)
- maxActive: 생성할 커넥션 수
- maxIdle: 일반적으로 활용할 커넥션 수
- maxWait: 커넥션 요청 대기 시간
WAS가 설치된 경로에 /conf/context.xml 파일을 편집합니다.
마찬가지로 이클립스에서는 server.xml이 있던 경로에 있습니다.
<Context>
<!--생략 -->
<ResourceLink global="jdbc/myoracle" name="jdbc/myoracle" type="javax.sql.DataSource" />
</Context>
server.xml에 등록했던 jdbc/myoracle 이란 이름으로 웹 어플리케이션에서 찾아서 사용할 수 있도록 글로벌한 이름을 지정해 줍니다.
web.xml 설정
서버측 설정(server.xml과 context.xml)에 등록한 리소스를 웹어플리케이션에서 사용하기 위하여 /WEB-INF/web.xml 파일에도 설정을 해줍니다.
<web-app> 태그 안쪽에 넣으시면 됩니다.
<!--생략 -->
<resource-ref>
<description>Oracle Datasource example</description>
<res-ref-name>jdbc/myoracle</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!--생략 -->
이제 준비가 끝났으니 커넥션 풀을 이용한 DB작업 예제를 작성해보겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.sql.*" %>
<%@ page import="javax.sql.*" %>
<%@ page import="javax.naming.*" %>
<%
//JNdI 서버 객체 생성
InitialContext ic = new InitialContext();
//JNDI lookup()
DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/myoracle");
//getConnectin()
Connection conn = ds.getConnection();
//쿼리 실행
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from TABLE_1");
while(rs.next()){
out.print("<br>"+rs.getString("sabun")+" : "+rs.getString("name"));
}
//자원 반납
rs.close();
stmt.close();
conn.close();
%>
java.sql 패키지는 일반 DB작업을 위해 import 했습니다.
javax.sql 패키지는 DataSource 객체를 사용하기 위해 import 했습니다.
javax.naming 패키지는 JNDI 작업을 위해 import 했습니다.
커넥션 풀에 접근하려면 JNDI 서비스를 사용해야 합니다.
JNDI는 리소스에 관한 정보를 알고 있어서 특정 리소스를 사용할 수 있도록 객체를 반환하는 역할을 합니다.
lookup()에서 우리가 찾으려는 리소스 이름은 "jdbc/myoracle"로 지정했었습니다.
그래서 lookup("jdbc/myoracle")로 실행해야 하는데 톰캣을 사용하는 경우 리소스를 관리하는 가상의 디렉토리가 있는데 그 경로가 java:comp/env 입니다. 그래서 리소스 이름앞에 추가로 지정해준 것입니다.
lookup()메소드는 리턴 타입이 Object이기 때문에 DataSource 타입으로 캐스팅 해주었습니다.
이후 내용은 커넥션을 얻고 DB작업을 완료 후 자원을 반납하는 과정입니다.
'DEV&OPS > Java' 카테고리의 다른 글
클래스 기반 커스텀 태그 JSP 1.2 (0) | 2022.07.05 |
---|---|
EL (Expression Language) (0) | 2022.07.01 |
표준 액션 태그 jsp java beans (0) | 2022.06.22 |
JSP 내장 객체 (0) | 2022.06.21 |
JSP (0) | 2022.06.20 |