쿼리의 결과를 cursor를 이용해서 다룰 수 있도록 하는 객체이다.
쿼리의 결과를 테이블 형태로 받아 특정 row를 가르키는 cursor를 가진다.
왜 테이블 형태로 받는가? -> 쿼리의 결과를 배열로 주면? -> 쿼리의 결과가 대규모일 경우 애플리케이션의 메모리에 모두 로드할 수 없을 수 있음.
커서는 방향성이 있으며 초기값은 첫번째 row의 이전을 가르키고 있음.
Javadoc ← 참고
public boolean next()
public boolean previous()
public boolean first()
public boolean last()
public boolean absolute(int row)
public boolean relative(int row)
public int getInt(int columnIndex)
public int getInt(String columnIndex)
public String getString(int columnIndex)
public String getString(String columnIndex)
public Blob getBlob(int columnIndex)
public Blob getBlob(String columnIndex)
public Clob getclob(int columnIndex)
public Clob getclob(String columnIndex)
위키백과
Plain Old Java Object, 간단히 POJO는 말 그대로 해석을 하면 오래된 방식의 간단한 자바 오브젝트라는 말로서 Java EE 등의 중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 "무거운" 객체를 만들게 된 것에 반발해서 사용되게 된 용어이다. 2000년 9월에 마틴 파울러, 레베카 파슨, 조쉬 맥킨지 등이 사용하기 시작한 용어로서 마틴 파울러는 다음과 같이 그 기원을 밝히고 있다.“ 우리는 사람들이 자기네 시스템에 보통의 객체를 사용하는 것을 왜 그렇게 반대하는지 궁금하였는데, 간단한 객체는 폼 나는 명칭이 없기 때문에 그랬던 것이라고 결론지었다. 그래서 적당한 이름을 하나 만들어 붙였더니, 아 글쎄, 다들 좋아하더라고. ”
— 마틴 파울러
중량 프레임워크들의 특정 기술과 환경에 종속되어 의존하게 된 자바 코드는 가독성이 떨어져 유지보수에 어려움이 생겼고 객체지향 설계의 장점들을 잃어버리게 됐습니다.
그에 반발해 생긴 POJO는 본래 자바의 장점을 살리는 '오래된' 방식의 '간단한' 자바 오브젝트를 의미합니다.
자바는 객체지향 언어이다. 매번 코드로 SQL의 쿼리를 짜려면 효율성과 가독성이 떨어진다.
→ ResultSet의 결과를 Java Object로 만들면 타입 안정성과 객체지향 프로그래밍의 장점을 살려서 프로그램을 간결하게 만들 수 있다.
JDBC 개요 에서 만들었던 테이블과 Java 코드를 이용하겠습니다.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class main {
public static void main(String[] args) {
try {
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/jdbc", "root", "1234");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from product");
while (rs.next()) {
System.out.println(
rs.getInt(1) + " " + rs.getString(2) + " " + rs.getDate(3)
+ " " + rs.getString(4) + " " + rs.getInt(5));
}
con.close();
}catch (Exception e) {System.out.println(e);}
}
}
import java.time.LocalDate;
public class Product { // 객체 = 인스턴스
int id;
String name;
LocalDate updatedAt;
String contents;
int price;
public void setPrice(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
Product(int id, String name, LocalDateTime updatedAt, String contents, int price) {
this.id = id;
this.name = name;
this.updatedAt = updatedAt.toLocalDate();
this.contents = contents;
this.price = price;
}
@Override
public String toString() { // 객체의 속성 출력을 위해서 String으로 concat
return id + " " + name + " " + updatedAt + " " + contents + " " + price;
}
}
import java.sql.ResultSet;
import java.sql.SQLException;
public class ResultSetMapper {
public static Product create(ResultSet rs) throws SQLException {
return new Product( // Product의 생성자에 각 레코드의 속성을 넣어준다.
rs.getInt(1), rs.getString(2), rs.getTimestamp(3).toLocalDateTime()
,rs.getString(4) , rs.getInt(5));
}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class Main {
public static void main(String[] args) {
try {
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/jdbc", "root", "1234");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from product");
while (rs.next()) {
System.out.println(ResultSetMapper.create(rs)); // 변경해준 부분
}
con.close();
}catch (Exception e) {System.out.println(e);}
}
}
표준입출력에 객체를 넣으면 toString() method를 자동으로 호출합니다.
모든 class는 Java의 Object
를 자동으로 상속 받고 Product
class 내에서 toString()을 오버라이딩 했기 때문에 다음과 같이 출력합니다.
1 shoes1 2022-08-01 This is shoes1 40000
2 shoes2 2022-08-01 This is shoes2 50000
3 shoes3 2022-08-01 This is shoes3 60000
4 shoes4 2022-08-01 This is shoes4 40000
5 shoes5 2022-08-01 This is shoes5 50000
6 shoes6 2022-08-01 This is shoes6 60000
7 backpack 2022-08-02 This is backpack 1500
8 shirt 2022-08-03 This is shirt 20000
9 glasses 2022-08-04 This is glasses 10000
while (rs.next())
{
System.out.println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getDate(3) + " "
+ rs.getString(4)
+ " " + rs.getInt(5));
}
위 코드와 같이 컬럼의 타입을 외워 매번 코딩할 필요 없이 DB의 데이터를 사용할 수 있음
SELECT문의 결과에 따라 별도의 Java Class로 선언해야 한다.
예를 들어 JOIN을 할 경우 나온 임시 테이블 레코드의 속성이 매번 다를 수 있음
이런 경우 코드를 짜는데 시간이 오히려 많이 들어간다. 또한 ResultSet은 index별로 타입을 구분해서 호출해야하므로 쿼리나 코드변경에 취약하다. (변경시 버그가 발생할 확률이 높아진다.)
이런 단점 때문에 ResultSet과 POJO class를 매핑하는 코드를 매번 짜는 것이 불편해서 ORM (Object-Relational Mapping) Library가 만들어졌다.
ORM은 객체와 Realational Model(관계형 데이터베이스 모델)을 매핑할 수 있는 기능을 가지고 있다.
하나의 테이블이 하나의 Java Class에 해당하고, FK와 같은 부가적인 기능(JOIN과 같은 참조기능)은 함수로 제공한다.