현 블로그는 모바일 환경이 아닌 PC환경에 최적화 되어있습니다.

 Mir의 운영환경

이전 챕터에서 우리는 DB접속까지 배워보았다. 이제 남은것은 3가지이다.
다시 한번말하지만 DB와의 연결과 실행시 꼭 지켜야될 5가지순서를 꼭 기억해두길 바란다. 

1. Drivers Loding
2. DB접속

3. SQL실행 준비
4. SQL실행
5. DB접속 종료

자 그럼 SQL실행 준비를 해보자.



3.SQL실행 준비
자 DB를 연결 한뒤 무엇을 해야 될까?
sql구문을 적어서 DB에 전송하여 그 sql문에 대한 값을 가져오면 되는것이다.

sql구문을 데이터베이스로 전송하기 위해서는 Statement타입의 객체를 이용해야 한다.
Statement 객체는 차라고 생각하면 된다.
Connection으로 DB에 연결하는 길을 열어 놨으면 그 길로 명령을 나르고 값을 받아오는 차가 Statement 객체이다.

Statement stmt = conn.createStatement();
stmt객체를 생성하기위해선 Connection 인터페이스의 creteStatement(); 메소드를 사용해야한다.


4-1. SQL구문 실행(executeUpdate)
그렇게 stmt객체를 생성하고 난뒤
executeUpdate( SQL구문 ) 혹은 executeQuery( SQL구문 ) 메소드를 사용하여 sql구문을 실어 나른다.
두 메소드의 차이점은
executeUpdate( ) 는 sql구문을 나르고 난뒤 몇개의 로우가 수정 및 추가되었는지 int형의 반환값을 가져오지만
executeQuery( )  는 sql구문을 나르고 난뒤 sql구문에 의해 실행되는 테이블, ResultSet형의 반환값을 가져온다.

필자는 우선 table에 값을 넣는 쿼리문을 적어넣을려고 하기때문에 executeUpdate( ) 메소드를 사용하겠다.
(이전에 테이블을 하나 만들어 놓자 테이블 이름은 test 컬럼은 name varchar(10), age int, joindate date 로 3개를 만들자)

자 그럼 쿼리문을 한번 날려보자.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;


public class InsertTest {

private String driver = "oracle.jdbc.driver.OracleDriver";

private String url = "jdbc:oracle:thin:@IP:포트:DBNAME";

private String dbid = "";

private String dbpass = "";

public InsertTest(){

try {

Class.forName(driver);

System.out.println("연결완료");

catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

private int Insert(String name, int age){

int x = 0;

try {

Connection conn = DriverManager.getConnection(url, dbid, dbpass);
                        Statement stmt = conn.createStatement(); 

                        String sql ="insert into jdbctest ";

      sql +=" values('" +name+ "'," +age+ ", sysdate)";                                    // 여기까지가 실행준비  

 

          //4. SQL문 실행

x = stmt.executeUpdate(sql); 

} catch (SQLException e) {

e.printStackTrace();

}

return x;

}

public static void main(String[] args) {

InsertTest it = new InsertTest();

int x = it.Insert("mir", 26);

if(x == 0)

System.out.println("생성실패!!!");

else

System.out.println("생성완료!!!");

}

}

자 다시한번 메인메소드 부터 보도록 하자.
우선 InsertTest 객체를 생성하면서 드라이버를 로딩하였다.
그리고 난뒤 Insert( ) 메소드를 실행하며 인자로 mir와 26을 주었다. 

다시 올라가서 Insert( )메소드는 mird와 26을 인자로 받고 난뒤
Connecton객체를 생성하면서 DB와 연결을 하고
Statement객체를 생성하여 DB에 명령어를 실어나를 차를 준비하였다.
실행 준비 마지막으로 String변수 sql을 생성하여 sql구문을 넣어두었다.

그리고 난뒤 executeUpdate( )메소드를 사용하여 sql구문을 실행하였다.
executeUpdate( )메소드는 몇개의 로우가 수정및 추가가 되는지 가져온다.
만약 정상적으로 Insert구문이 추가되었으면 1의 값을 가져올것이다.
그 1이란 값을 변수 x에 담아 리턴값으로 주었다
 
Insert( )메소드를 다 실행시키고 난뒤 메인메소드에서 x에 1의 값을 리턴 받고 난뒤
if문을 거친다.
만약 x의 Insert구문이 정상적으로 추가가 되어 1의 값을 가져왔으면 생성완료라고 뜰것이고
추가가 되지 않고 0의 값을 가져왔으면 생성실패라고 뜰것이다.


4-2. SQL구문 실행(executeQuery)
자 그럼 다음엔 executeQuery( )메소드를 사용하여 내가 추가한 구문이 제대로 들어갔는지 확인해 보자.
executeQuery( )메소드를 사용할때에는 실행과정이 하나더 생기게 된다.
결과값으로 ResultSet형을 가져오기 때문에 그 값을 받을 ResultSet형 참조변수를 만들줘야 한다.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;


public class SelectTest {

private String driver = "oracle.jdbc.driver.OracleDriver";

private String url = "jdbc:oracle:thin:@IP:포트:DBNAME";

private String dbid = "";

private String dbpass = "";

public SelectTest(){

try {

Class.forName(driver);

System.out.println("연결완료");

catch (ClassNotFoundException e) {

e.printStackTrace();

}

}


         private
void Select() {

try {

Connection conn = DriverManager.getConnection(url, dbid, dbpass);

Statement stmt = conn.createStatement();

String sql = "select * from jdbctest";
 

// 여기까지가 실행준비

// 4. SQL 실행

ResultSet rs = stmt.executeQuery(sql);


System.out.println("이름\t나이\t가입날짜");

while (rs.next()) {

String nm = rs.getString("name");

int age = rs.getInt("age");

String jd = rs.getString(3);

System.out.println(nm + "\t" + age + "\t" + jd);

}

} catch (SQLException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

SelectTest2 st = new SelectTest2();

st.Select();

}

}


자 위의 예제를 보면 실행준비까지는 executeUpdate( )를 사용한 예제와 거의 다른점이 없다.
다만 Seatement객체로 SQL구문을 실어 나를때 executeQuery( )를 사용하였고
그 값을 ResultSet의 객체로 값을 받았다.

우리가 SELECT쿼리문을 데이터베이스 내에서 사용할때 보면 표와같이 화면에 나오는것을 확인할수 있다.
그것을 JDBC에서는 ResultSet형이라고 표현하며 그 표를 모두 rs라는 ResultSet객체에 담는 것이다.

자 그러면 이제 받아온 값을 출력을 해야 하는데
그냥 int형이나 String형을 받아왔으면 바로 print( )구문으로 출력을 하면 되지만
ResultSet형은 표처럼 되어 있기때문에 바로 출력을 해줄수 없다.

그래서 각 getString( )나 getInt( )같은 메소드를 사용하여 그 값을 하나하나 꺼내야 한다.
getString( )나 getInt( )같은 메소드에 인자값을 컬럼명으로 주면 그 컬럼에 있는 값을 가져오게 된다.
위 예제에서는 String nm에 getString( "name" )이란 메소드를 사용하여 name컬럼에 있는 값을 가져왔다.
마찬가지로 getInt("age")란 메소드로 age컬럼에 있는 값을 int age에 넣었다.

여기서 하나의 문제점이 만약 name컬럼에서 getString("name)"을 사용하여 값을 가져오는데
테이블(ResultSet형)에서 어떤 값을 가져와야 될지 모른다.

그때 사용하는 메소드가 next( )메소드이다.
쉽게 표현하면 우리가 SELECT 쿼리문으로 값을 불러서 가져왔을때 rs(ResultSet)의 커서는 컬럼명을 가르키고 있다.
그래서 그 커서를 next( )메소드로 한칸 아래로 내려주는 것이다.
자 그럼 커서를 next( )를 사용하여 한칸 내려주면 우리가 검색한 값의 첫번째 라인을 선택하게 된다.
while문을 사용하여 계속 내리다 보면 표에서 벗어나게 되는데
next( )메소드는 표에서 한칸씩 커서를 내리면서 다음행이 있으면 true를 다음행이 없으면 false를 반환하게 된다.

결국 while문을 사용하여 마지막줄까지의 데이터를 출력하고 false값을 얻어 반복구문이 멈추게 되는것이다.

5. DB접속 종료
JDBC에서는 접속종료(자원 반환)이 매우 중요하다.
객체가 더이상 쓰이지 않을 때 가베지 컬렉터가 동작하여 객체를 회수하지만
객체자체가 열심히 동작하고 있다고 판단되면 가베지 컬렉터는 그 객체를 회수하지 않는다.

JDBC와 관련된 객체가 이러한 특성을 지니는데
따라서 JDBC 프로그래밍에서 작업이 끝나면 반드시 생성된 객체의 자원을 반환하는 코드를 작성해주어야 한다.
반환을 할때에는 close( )메소드를 사용하는데 여기서 주의할점이 우리가 생성했던 순서의 반대로 반환을 해주어야 한다.

ResultSet객체를 먼저 반환하고 Statement 객체를 반환하고 난뒤 Connection객체를 반환해주어야 한다.
rs.close( );
stmt.close( );
conn.close( ); 
자 생각해보자.
Connection으로 DB까지의 길을 만들고 난뒤 Statement로 sql을 구문을 실어 나른다.
그런데 차를 반환하기 전에 먼저 길을 없애버리면 그 차는 어떻게 될까?
이러한 개념을 가지고 있으면 실수할일이 없어질것이다.

그럼 객체 반환을 한번 시켜보자. 

private int Insert(String name, int age){

int x = 0;

try {

Connection conn = DriverManager.getConnection(url, dbid, dbpass);

                        Statement stmt = conn.createStatement(); 

                        String sql ="insert into jdbctest ";

      sql +=" values('" +name+ "'," +age+ ", sysdate)";                                    // 여기까지가 실행준비  

 

        //4. SQL문 실행

x = stmt.executeUpdate(sql); 

stmt.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return x;

}

위 InsertTest클래스의 Insert( )메소드만 불러왔다.

자 위와같이 close( )메소드를 사용하여 각 객체를 반환해주면 되는데 한가지 문제점이 생긴다.

어떤 문제냐면 Connection객체만 생성하고 난뒤 Exception이 일어나게 되면
close( )명령을 건너뛰고 try구문을 빠져나가게 되는것이다.

그래서 반환명령은 try구문의 finally뒤에 적어주는게 제일 좋은데 stmt나 conn은 try안의 지역변수이기 때문에 
try구문을 들어가기전 변수를 생성해주도록 하자.

private int Insert(String name, int age) {

int x = 0;

Statement stmt = null;

Connection conn = null;

try {

conn = DriverManager.getConnection(url, dbid, dbpass);

stmt = conn.createStatement();

String sql = "insert into jdbctest ";

sql += " values('" + name + "'," + age + ", sysdate)"; // 여기까지가 실행준비


// 4. SQL문 실행

x = stmt.executeUpdate(sql);


} catch (SQLException e) {

e.printStackTrace();

} finally {


try {

if (stmt != null)

stmt.close();

if (conn != null)

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}


}

return x;

}

위와 같이 if문을 사용하여 각 객체가 null이 아닐때만 close를 해주도록 하면 또 다른 Exception을 미연에 방지해줄수도 있다.

자 그럼 JDBC로 데이터베이스에 연결하고 해제하는것까지 배워보았다.
여기서 한가지 팁을 주자면 jdbc에 연결할때 공통되는 명령을 메소드로 만들어 두면
훨씬 편하게 작업을 할수 있을것이다.

각자 한번 접속과 해제에 대한 메소드를 만들어 보는것도 좋을것이다.




----- 필자의 memo
* 검색테이블 기준(검색을 출력하는 가상의 테이블)으로 값을 가져온다. *

rs = 주소값 (전체테이블을 가르키고 있음)  = 커서 = 커서는 컬럼명에 있따.

first( )는 커서를 제일 위로 옮긴다.
될수있으면 string으로 접근 - 컬럼순서(int)로 넘어가면 만약 120개의 컬럼을 가지고 있으면 일일이 세어봐야 된다.

select name and, age as a;
위와 같을때에는 컬럼명이 n으로 바꾸었기때문에 n을 기입해야 한다.

 previous()는 커서를 위로!
하지만 result를 아무 셋팅 하지 않으면  type_forward_only 이기때문에 next만 된다. 
설정을 하면 type_scroll_insensitive or type_scroll_sensitive 이것을 설정하면 된다... (어떻게 설정하는지는 잘 모름)

 ----- memo


+ Recent posts