1) article write시
SecSql의 객체 .append()를 이용해 쿼리문을 작성하고
DBUtil.insert메소드를 통해 DB에 추가
SecSql sql = new SecSql();
sql.append("INSERT INTO article");
sql.append(" SET regDate = NOW()");
sql.append(", updateDate = NOW()");
sql.append(", title = ?", title);
sql.append(", `body` = ?", body);
DBUtil.insert(conn, sql);
2) article modify시
write와 마찬가지로 sql객체로 쿼리문을 담고
DBUtil.update메소드를 통해 수정
SecSql sql = new SecSql();
sql.append("UPDATE article");
sql.append(" SET updateDate = NOW()");
sql.append(", updateDate = NOW()");
sql.append(", title = ?", title);
sql.append(", `body` = ?", body);
sql.append(" WHERE id = ?", id);
DBUtil.update(conn, sql);
3) article list시
쿼리문을 담는 방식은 동일하고
DBUtil.selectRows(conn, sql)메소드는 반환값이 List<Map<String, Object>>이다.
Map 리스트이므로 반복문을 통하여 Map객체를 하나씩 꺼내 articles에 추가하였다.
이때 Article객체 생성시 articleMap(Map형태)를 매개변수로 받을수 있게 생성자도 추가
List<Article> articles = new ArrayList<>();
SecSql sql = new SecSql();
sql.append("SELECT *");
sql.append(" FROM article");
sql.append(" ORDER BY id DESC");
List<Map<String, Object>> articlesListMap
= DBUtil.selectRows(conn, sql);
for(Map<String, Object> articleMap : articlesListMap) {
articles.add(new Article(articleMap));
}
Article생성자 추가 코드
public Article(Map<String, Object> articleMap) {
this.id = (int)articleMap.get("id");
this.title = (String)articleMap.get("title");
this.body = (String)articleMap.get("body");
}
else if (cmd.startsWith("article delete ")) {
int id = Integer.parseInt(cmd.split(" ")[2]);
SecSql sql = new SecSql();
sql.append("SELECT COUNT(*) FROM article");
sql.append(" WHERE id = ?", id);
int articlesCount = DBUtil.selectRowIntValue(conn, sql);
if (articlesCount == 0) {
System.out.printf("%d번 게시글은 존재하지 않습니다.\n", id);
return 0;
}
System.out.printf("== %d번 게시물 삭제 ==\n", id);
sql = new SecSql();
sql.append("DELETE FROM article");
sql.append(" WHERE id = ?", id);
DBUtil.delete(conn, sql);
System.out.printf("%d번 게시물이 삭제 되었습니다\n", id);
public static int selectRowIntValue(Connection dbConn, SecSql sql) {
Map<String, Object> row = selectRow(dbConn, sql);
for (String key : row.keySet()) {
return (int) row.get(key);
}
return -1;
}
else if (cmd.startsWith("article detail ")) {
int id = Integer.parseInt(cmd.split(" ")[2]);
System.out.printf("== %d번 게시물 상세보기 ==\n", id);
SecSql sql = new SecSql();
sql.append("SELECT *");
sql.append("FROM article");
sql.append("WHERE id = ?", id);
Map<String, Object> articleMap = DBUtil.selectRow(conn, sql);
if (articleMap.isEmpty()) {
System.out.printf("%d번 게시글은 존재하지 않습니다.\n", id);
return 0;
}
Article article = new Article(articleMap);
System.out.printf("번호 : %d\n", article.id);
System.out.printf("작성날짜 : %s\n", article.regDate);
System.out.printf("수정날짜 : %s\n", article.updateDate);
System.out.printf("제목 : %s\n", article.title);
System.out.printf("내용 : %s\n", article.body);
}
delete와 비슷한 방식으로 id로 해당하는 로우를 DBUtil.selectRow()메소드를 통해 찾고
articleMap에 key와 value의 값으로 담는다. 이때 Map타입의 articleMap을 전에 만들었던 Article()생성자의 인자로 넣으면 Article 객체를 생성할수 있다. article의 필드를 꺼내어 상세보기로 만듬.
주의할점
Article클래스의 필드 regDate와 updateDate는 String타입이다.
하지만 DB에서 article테이블의 regDate와 updateDate 타입은 DATETIME이다.
String타입으로 DATETIME타입을 담을수 없으므로 LocalDateTime타입으로 변경해야한다.
public static int insert(Connection dbConn, SecSql sql) {
int id = -1;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = sql.getPreparedStatement(dbConn);
stmt.executeUpdate();
rs = stmt.getGeneratedKeys();
if (rs.next()) {
id = rs.getInt(1);
}
return id;
}
public static List<Map<String, Object>> selectRows(Connection dbConn, SecSql sql) throws SQLErrorException {
List<Map<String, Object>> rows = new ArrayList<>();
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = sql.getPreparedStatement(dbConn);
rs = stmt.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnSize = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> row = new HashMap<>();
for (int columnIndex = 0; columnIndex < columnSize; columnIndex++) {
String columnName = metaData.getColumnName(columnIndex + 1);
Object value = rs.getObject(columnName);
if (value instanceof Long) {
int numValue = (int) (long) value;
row.put(columnName, numValue);
} else if (value instanceof Timestamp) {
String dateValue = value.toString();
dateValue = dateValue.substring(0, dateValue.length() - 2);
row.put(columnName, dateValue);
} else {
row.put(columnName, value);
}
}
rows.add(row);
}
return rows;
}
ResultSetMetaData metaData = rs.getMetaData(); : 메타데이터는 저장된 데이터가아니라 , 해당 데이터에 관한 정보를 갖는 데이터를 의미
Result 클래스의 rs.getMetaData() : 메소드를 이용하여 ResultSetMetaData 클래스 객체를 만들어 사용
metaData.getColumnName(index) : index는 1부터 시작한다. ResultSetMetaData의 컬럼명을 가져온다. 반환값은 String
ResultSetMetaData.getColumnCount() : 컬럼의 수를 가져옴
rs.getObject(columnName); : 컬럼명을이용해 result객체에서 컬럼에대한 값을 Object타입으로 가져옴
반복문을 통해 컬럼과 컬럼에 해당하는 값을 row(Map)에 Key와 Value로 put저장
이때 value의 값을 형변환해서 row에 저장 후 rows(List) List에 연결
ResultSet 자료 꺼내올때 궁금한점
Mysql의 자료형 타입에 따라 호출
- 예를 들어 id컬럼이 타입이 int이면 getInt()메서드를 사용하고
title 컬럼의 타입이 char이면 getString()메서드를 사용해야한다.
ResultSet, Cursor
- ResultSet은 excuteQuery()메소드 실행한다음 반환되는 레코드셋을 저장한다
레코드셋은 가상의 데이터베이스 테이블 형태이다.- cursor로 데이터를 가져오는데 ResultSet객체가 가져올수 있는 행의 위치를 지정해준다
- 처음 커서의 위치는 결과물(필드)에 위치하지 않기 때문에 cursor를 이동해야한다
- 커서를 이동하는 역할은 Result next()메서드가 수행한다
- next()메서드의 리턴 타입은 boolean이다 다음행의 결과물이 있으면 true리턴
public static Map<String, Object> selectRow(Connection dbConn, SecSql sql) {
List<Map<String, Object>> rows = selectRows(dbConn, sql);
if (rows.size() == 0) {
return new HashMap<>();
}
return rows.get(0);
}
public static int selectRowIntValue(Connection dbConn, SecSql sql) {
Map<String, Object> row = selectRow(dbConn, sql);
for (String key : row.keySet()) {
return (int) row.get(key);
}
return -1;
}
public static String selectRowStringValue(Connection dbConn, SecSql sql) {
Map<String, Object> row = selectRow(dbConn, sql);
for (String key : row.keySet()) {
return (String) row.get(key);
}
return "";
}
public static boolean selectRowBooleanValue(Connection dbConn, SecSql sql) {
Map<String, Object> row = selectRow(dbConn, sql);
for (String key : row.keySet()) {
return ((int) row.get(key)) == 1;
}
return false;
}