세번째 ResultSet 객체에서 여러개의 행(row)를 받아 객체로 생성하고 리스트 객체로 전달하는 메소드인 executeQueryList()메소드를 생성하겠습니다.
PreparedStatement에서 사용되는 쿼리문
SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10
쿼리문처럼 조건 없이 전체를 카운트 할 수 있어 전달되는 객체가 없을 수 있습니다.
executeQueryList()메소드는executeQueryOne()메소드와 동일하지만 결과가 리스트 객체로 전달됩니다.
데이터베이스 컨넥션 객체를 가져옵니다.
Connection connection = getConnection();
createPreparedStatement()메소드를 이용하여 PreparedStatement를 생성합니다.
PreparedStatement preparedStatement = createPreparedStatement(connection, query, parameterObject);
if (preparedStatement != null) {
System.out.println("PreparedStatement를 생성함");
} else {
System.out.println("PreparedStatement를 생성하지 못함");
}
자세한 설명은 "자바 패턴 매치와 리플렉션을 이용한 자동 PreparedStatement 생성 1"를 참조하세요.
생성된 PreparedStatement를 실행하여 ResultSet 객체를 받습니다.
ResultSet resultSet = preparedStatement.executeQuery();
ResultSet 객체의 전체 행(row)들을 리턴하기 위해 전달 받은 클래스로 리스트 객체를 생성합니다.
List<T> resultTypeList = new ArrayList<T>();
while문으로 ResultSet 객체의 전체 행(row)들을 전달 받은 클래스로 새로운 인스턴스를 생성합니다.
while (resultSet.next()) {
T resultTypeInstance = null;
try {
resultTypeInstance = resultTypeClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
생성된 객체에서 맴버 필드 리스트를 가져옵니다.
Field[] Fields = resultTypeClass.getDeclaredFields();
ResultSet 객체에서 컬럼(column)의 메타정보를 가져옵니다.
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
ResultSet 객체의 컬럼과 일치하는 객체의 맴버 필드를 찾고 맴버 필드에 접근할 수 있게 설정하여 맴버 필드에 값을 설정합니다.
for (int index = 1; index <= resultSetMetaData.getColumnCount(); index++) {
String columnLabel = resultSetMetaData.getColumnLabel(index);
for (Field field : Fields) {
if (field.getName().equals(columnLabel)) {
field.setAccessible(true);
try {
field.set(resultInstance, resultSet.getObject(index));
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
생성된 객체를 리스트 객체에 추가합니다.
resultTypeList.add(resultTypeInstance);
PreparedStatement를 종료합니다.
preparedStatement.close();
데이터베이스 컨넥션 객체를 반환하고 결과로 리스트 객체를 리턴합니다.
closeConnection(connection);
return resultTypeList;
1. "TestDatabaseDataSource.java"나 "TestDatabaseJNDI.java", "TestDatabaseConectionPool.java", "TestDatabasePoolManager.java", "TestDatabaseManager.java"에 추가하시면 됩니다.
executeQueryList()메소드에서 전달되는 클래스로 결과를 생성하여 리턴하기 위해 제네릭 메소드로 생성합니다.
추가되는 전체 소스입니다.
/**
* 쿼리문(SELECT)을 실행한다.
* @param query 쿼리 문자열
* @param parameterObject 파라미터 객체
* @param resultTypeClass 결과 클래스
* @return 결과 값
*/
public <T> List<T> executeQueryList(String query, Object parameterObject, Class<T> resultTypeClass) {
List<T> resultTypeList = null;
long startTime = System.currentTimeMillis();
Connection connection = getConnection();
PreparedStatement preparedStatement = createPreparedStatement(connection, query, parameterObject);
if (preparedStatement != null) {
System.out.println("PreparedStatement를 생성함");
try {
ResultSet resultSet = preparedStatement.executeQuery();
resultTypeList = new ArrayList<T>();
if (resultTypeClass != null) {
while (resultSet.next()) {
T resultTypeInstance = null;
if (resultTypeClass != null) {
try {
resultTypeInstance = resultTypeClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
if (resultTypeInstance != null) {
Field[] Fields = resultTypeClass.getDeclaredFields();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
for (int index = 1; index <= resultSetMetaData.getColumnCount(); index++) {
String columnLabel = resultSetMetaData.getColumnLabel(index);
for (Field field : Fields) {
if (field.getName().equals(columnLabel)) {
field.setAccessible(true);
try {
field.set(resultTypeInstance, resultSet.getObject(index));
System.out.println("객체의 " + field.getName() + "에 값(" + resultSet.getObject(index) + ")을 적용함");
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
resultTypeList.add(resultTypeInstance);
}
System.out.println("Query[" + preparedStatement.toString() + "]를 실행함");
}
resultSet.close();
} catch (SQLException e) {
resultTypeList = null;
System.out.println("Query[" + preparedStatement.toString() + "]를 실행하지 못함");
e.printStackTrace();
}
try {
preparedStatement.close();
System.out.println("PreparedStatement를 종료함");
} catch (SQLException e) {
System.out.println("PreparedStatement를 종료하지 못함");
e.printStackTrace();
}
} else {
System.out.println("PreparedStatement를 생성하지 못함");
}
closeConnection(connection);
long endTime = System.currentTimeMillis();
System.out.println((endTime - startTime) + "ms 소요됨");
return resultTypeList;
}
2. "TestLoginDaoImpl.java"의 getMemberList()메소드를 executeQueryList()메소드로 처리되게 변경합니다.
@Override
public List<UserVO> getMemberList() {
List<UserVO> list = null;
String query = "SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10";
Connection connection = testDatabaseManager.getConnection();
if (connection != null) {
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(query);
System.out.println("PreparedStatement를 생성함");
} catch (SQLException e) {
System.out.println("PreparedStatement를 생성하지 못함");
e.printStackTrace();
}
if (preparedStatement != null) {
ResultSet resultSet = null;
try {
resultSet = preparedStatement.executeQuery();
System.out.println("Query[" + preparedStatement.toString() + "]를 실행함");
} catch (SQLException e) {
System.out.println("Query[" + preparedStatement.toString() + "]를 실행하지 못함");
e.printStackTrace();
}
try {
while (resultSet.next()) {
UserVO selectUserVO = new UserVO();
selectUserVO.setId(resultSet.getString("MBR_ID"));
selectUserVO.setName(resultSet.getString("MBR_NM"));
list.add(selectUserVO);
}
resultSet.close();
if (list.size() <= 0) {
System.out.println("resultSet이 없음");
}
} catch (SQLException e) {
System.out.println("resultSet를 가져오지 못함");
e.printStackTrace();
}
try {
preparedStatement.close();
System.out.println("PreparedStatement를 종료함");
} catch (SQLException e) {
System.out.println("PreparedStatement를 종료하지 못함");
e.printStackTrace();
}
}
testDatabaseManager.closeConnection(connection);
}
return list;
}
변경된 소스입니다.
@Override
public List<UserVO> getMemberList() {
List<UserVO> list = null;
String query = "SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10";
list = (List<UserVO>)testDatabaseManager.executeQueryList(query, null, UserVO.class);
return list;
}
3. 이전 "자바 JUnit를 이용한 단위 테스트"에서 추가한 "TestLoginDaoImplTest.java"에서 테스트 케이스인 testGetMemberList()메소드에서 getMemberList()메소드를 실행할 수 있게 수정합니다.
/**
* Test method for {@link com.home.project.test2.dao.TestLoginDaoImpl#getMemberList()}.
*/
@Test
public void testGetMemberList() {
System.out.println("testGetMemberList() 테스트 시작");
List<UserVO> userList = testLoginDao.getMemberList();
for (UserVO userVO : userList) {
System.out.println("사용자 ID : " + userVO.getId());
System.out.println("사용자 이름 : " + userVO.getName());
}
System.out.println("testGetMemberList() 테스트 성공 종료");
}
4. test2 프로젝트의 [Java Resources > src/test/java]에 있는 "com.home.project.test2.util > TestLoginDaoImplTest.java"에서 마우스 오른쪽 버튼을 클릭하여 콘텍스트 메뉴에서 [Run As > JUnit Test]를 클릭합니다.
JUnit Test가 실행되면서 왼쪽에 JUnit탭이 나타나고 Error가 "0", Failures이 "0"으로 테스트가 성공합니다.
[Console]
testGetMemberList() 테스트 시작
[main] 데이터베이스 커넥션 객체[24433162, URL=jdbc:mariadb://localhost:3306/test, MariaDB Connector/J]를 가져옴
PreparedStatement를 생성함
객체의 id에 값(testid)을 적용함
객체의 name에 값(홍길동1)을 적용함
Query[sql : 'SELECT MBR_ID AS id, MBR_NM AS name FROM MBR_ACCOUNT_TB LIMIT 0, 10', parameters : []]를 실행함
PreparedStatement를 종료함
[main] 데이터베이스 커넥션 객체[24433162, URL=jdbc:mariadb://localhost:3306/test, MariaDB Connector/J]를 반환함
27ms 소요됨
사용자 ID : testid
사용자 이름 : 홍길동1
testGetMemberList() 테스트 성공 종료
이제 PreparedStatement 자동 생성과 실행으로 DAO에서는 쿼리문만 집중해서 작성하게 되었습니다.
또한 반복적인 코드를 줄임으로써 개발 시간이 단축되었습니다.