★ ResultSet
DB에 JDBC 드라이버를 이용하여 SQL의 수행을 요청하고 결과를 받아 내는 인터페이스이다.
JDBC 2.0 API에는 SQL 수행 결과를 스크롤되는 ResultSet으로도 저장할 수 있도록 한다.
■ next() - 다음 데이터
■ previous() - 이전 데이터
■ first() - 맨 처음 데이터
■ last() - 맨 마지막 데이터
■ beforeFirst() - 제일 처음 위치
■ afterLast() - 맨 마지막 위치
■ absolute(int row) - 절대 위치로 간다. 시작부터 계산해서 row행으로.
■ relative(int row) - 현재 위치를 기준으로 이동한다.
현재 위치 + row행으로.
■ deleteRow()
■ insertRow()
■ updateRow()
……
……
ScrollableResultSet :
ResultSet을 스크롤 가능하게 만들어 커서를 원하는 레코드로 옮길 수도 있다.(JDBC 2.0)
UpdateableResultSet :
ResultSet에서의 데이터 변경을 데이터베이스에 반영하도록 하는 기능을 제공.(JDBC 2.0)
■ ResultSet.TYPE_SCROLL_SENSITIVE
ResultSet스크롤 가능하며 업데이트가 발생하면 바로 데이터베이스에 반영된다.
■ ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet스크롤 가능하며 업데이트가 발생해도 데이터베이스에 반영되지 않는다.
■ ResultSet.TYPE_FORWARD_ONLY
ResultSet 스크롤이 되지 않으며 다음 Row만 진행된다.
Default값.
■ ResultSet.CONCUR_UPDATABLE
ResultSet에서 데이터 변경을 가능하도록 설정한다.
■ ResultSet.CONCUR_READ_ONLY
ResultSet에서 데이터 변경을 불가능하고 조회만 가능하도록 설정한다.
Default값.
/******************************************************************************
* 파일 : RS_Scroll.java
* 용도 : ResultSet 을 Scroll 가능하게 해서 테스트하는 예제
* 작성자 : 성홍제
* 작성일 : 2006. 07. 27
* Version : 1.0
******************************************************************************/
package ResultSet;
import java.sql.*;
import ConnectionPool.DBConnectionMgr;
public class RS_Scroll
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
DBConnectionMgr mgr = DBConnectionMgr.getInstance();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "select * from test10_tbl";
try
{
conn = mgr.getConnection();
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
/*
* ResultSet_Type ResultSet_Concurrency
* TYPE_FORWARD_ONLY CONCUR_READ_ONLY
* TYPE_SCROLL_INSENSITIVE CONCUR_UPDATABLE
* TYPE_SCROLL_SENSITIVE
*/
rs = pstmt.executeQuery();
// rs를 맨 위에서부터 순차적으로 탐색한다.
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
System.out.println("순차탐색 끝");
// rs가 afterLast에 있지않으면 - afterLast로 보낸다.
if(rs.isAfterLast())
rs.afterLast();
// rs를 맨 밑에서부터 역순으로 탐색한다.
while(rs.previous())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
System.out.println("역순탐색 끝");
// rs를 5번째 행으로 보낸다. 절대위치로 이동
rs.absolute(5);
// 5번으로 이동한 후, 그 이전 것 즉, 4번부터 출력한다.
while(rs.previous())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
System.out.println("절대위치로 이동후, 역순으로 탐색 끝");
// 맨 위로 이동해 있는 rs를 상대적으로 이동시키려 했으나, 오류 발생
// java.sql.SQLException: 현재 행이 아닙니다: relative - 맨 위로 이동해서 현재 위치가
// beforeFirst라서 데이터가 없으므로 상대적으로 이동불가
// 따라서 rs.next를 해서 데이터가 있는 곳으로 간 뒤, 상대적으로 이동시킨다.
rs.next(); // 현재 위치 1번.
rs.relative(7); // 상대적으로 7칸 이동. 현재 위치 8번
rs.relative(-3); // 다시 위로 3칸 이동. 현재 위치 5번.
// 5번 다음 것부터 출력하므로 6번부터 나온다.
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
pstmt.close();
conn.close();
mgr.freeConnection(conn);
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
★ ResultSet의 TYPE_SCROLL_INSENSITIVE, TYPE_SCROLL_SENSITIVE,
CONCUR_UPDATABLE에 대해서
① stmt1(Statement개체)이 ResultSet을 INSENSITIVE, UPDATABLE로 생성한 후, 사용하는 경우
stmt1은 rs를 통해서 DB를 업데이트 할 수 있다.
하지만, stmt2(즉 다른 사용자라고도 볼 수 있는)가 DB를 바꾸었을 때, 그 바뀐 내용을 가져오지는못한다.
그래서
② SENSITIVE 옵션이 필요하다.
SENSITIVE 옵션을 주어 생성한 rs는 변경된 DB의 내용을 가져올 수 있다.
하지만, refreshRow() 메소드는 각 행별로 변경된 내용을 가져오므로, 미리 가져와서 사용하고 있는 rs의 행의 수와 변경된 DB의 행의 수가 다를 경우에는 문제가 생긴다.
/******************************************************************************
* 파일 : RS_InDel.java
* 용도 : ResultSet을 Update가능하게 해서 테스트하는 예제
* 작성자 : 성홍제
* 작성일 : 2006. 07. 27
* Version : 1.0
******************************************************************************/
package ResultSet;
import java.sql.*;
import ConnectionPool.DBConnectionMgr;
public class RS_InDel
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
DBConnectionMgr mgr = DBConnectionMgr.getInstance();
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "select num, id, name, age from test10_tbl";
try
{
conn = mgr.getConnection();
pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
/*
* ResultSet_Type ResultSet_Concurrency
* TYPE_FORWARD_ONLY CONCUR_READ_ONLY
* TYPE_SCROLL_INSENSITIVE CONCUR_UPDATABLE
* TYPE_SCROLL_SENSITIVE
*/
rs = pstmt.executeQuery();
// String sql = "select * from test10_tbl";
// - 데이터를 추가하기 위해서는 컬럼명을 직접 입력해줘야 한다.
// 이렇게 *로 하면 인식 못한다.
// 데이타 추가 ------------------------------------------------------
// 데이터를 추가하기 위해서 데이터 추가가 가능한 ROW로 이동. 맨 밑.
rs.moveToInsertRow();
rs.updateInt (1, 1001);
rs.updateString (2, "ID44");
rs.updateString (3, "JUNG");
rs.updateInt (4, 71);
rs.insertRow(); // 데이터를 추가한다. DB도 변경된다.
rs.moveToInsertRow();
rs.updateInt (1, 1002);
rs.updateString (2, "ID66"); // 2번까지만 넣어주면, 나머지는 이전에 사용했던 것들,
// 즉 (3, JUNG), (4, 71) 값이 들어가게 된다.
rs.insertRow();
//rs.close (); // 여기서 close 해버리면 밑에서 rs를 다시 얻기 전에는 사용불가.
//------------------------------------------------------------------
System.out.println ("데이타 추가 후 =============");
System.out.println ("지금 쓰고 있는 rs의 내용-----");
rs.beforeFirst();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// rs는 변경되었고 UPDATABLE 옵션이 있었으므로 DB도 변경되었다.
rs.close ();
System.out.println ("DB의 내용을 다시 받아온다.-----");
rs = pstmt.executeQuery();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// DB의 내용이 변경된 것을 볼 수 있다.
// 데이타 삭제 -----------------------------------------------------
if (!rs.isBeforeFirst())
{
rs.beforeFirst();
}
while (rs.next())
{
if (rs.getInt(1) == 1001)
{
rs.deleteRow();
break;
}
}
//rs.close ();
//-----------------------------------------------------------------
System.out.println ("데이타 삭제 후============ ");
System.out.println ("지금 쓰고 있는 rs의 내용-----");
rs.beforeFirst();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// 역시 마찬가지로 rs는 변경되었고 UPDATABLE 옵션이 있었으므로 DB도 변경되었다.
//rs.close ();
System.out.println ("DB의 내용을 다시 받아온다.-----");
rs = pstmt.executeQuery();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// DB의 내용이 변경된 것을 볼 수 있다.
// 테이블 원상태로 복원 -------------------------------------------
// 새롭게 생성한 stmt1이 DB의 내용을 변경한다.
// 이렇게 변경된 DB의 내용은 지금은 rs에 반영할 수 없다. SENSITIVE 옵션이 없으므로.
// 하지만 stmt가 사용하던 rs의 내용이 변경되지 않았다고 하더라도
// DB는 이미 변경된 상태이므로
Statement stmt1 = conn.createStatement ();
stmt1.execute("DELETE FROM test10_tbl WHERE num=1001 OR num=1002");
//stmt1.execute("COMMIT");
stmt1.close();
System.out.println ("데이타 복원 후============ ");
System.out.println ("지금 쓰고 있는 rs의 내용-----");
rs.beforeFirst();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// stmt가 사용하던 rs의 내용은 그대로이다.
rs.close ();
System.out.println ("DB의 내용을 다시 받아온다.-----");
rs = pstmt.executeQuery();
while(rs.next())
{
String s = "num: " + rs.getInt("num") + "\t" + "id: " + rs.getString("id") + "\t"
+ "name: " + rs.getString("name") + "\t" + "age: " + rs.getInt("age");
System.out.println(s);
}
// stmt1이 변경한 이후의 DB의 내용이 새롭게 rs에 들어간다.
// stmt1이 변경한 값이 DB에 반영되어 있는 것을 알 수 있다.
pstmt.close();
conn.close();
mgr.freeConnection(conn);
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}