[자바 JDBC 게시판] 2일차

김정현·2022년 8월 9일

JDBC게시판

목록 보기
7/9

1. 게시물 리스팅시 데이터를 DB에서 가져옴

	else if (cmd.equals("article list")) {
		    System.out.println("== 게시물 리스트 ==");
            Connection conn = null;
			PreparedStatement pstmt = null;
			ResultSet result = null;
			List<Article> articles = new ArrayList<>();

			try {
				Class.forName("com.mysql.jdbc.Driver");
				String url = "jdbc:mysql://127.0.0.1:3306/article_manager?useUnicode=true&char  acterEncoding=utf8&autoReconnect=true&serverTimezone=
                    Asia/Seoul&useOldAliasMetadataBehavior=true&zeroDateTimeNehavior=convertToNull";

				conn = DriverManager.getConnection(url, "root", "");
				System.out.println("연결 성공!");

				String sql = "SELECT * FROM article";
				sql += " ORDER BY id DESC;";

				System.out.println(sql);
				pstmt = conn.prepareStatement(sql);
				result = pstmt.executeQuery();

				while (result.next()) {
					int id = result.getInt("id");
					String regDate = result.getString("regDate");
					String updateDate = result.getString("updateDate");
					String title = result.getString("title");
					String body = result.getString("body");

					Article article = new Article(id, regDate, updateDate, title, body);

					articles.add(article);
				}
			} catch (ClassNotFoundException e) {
				System.out.println("드라이버 로딩 실패");
			} catch (SQLException e) {
				System.out.println("에러: " + e);
			} finally {
				try {
					if (result != null && !result.isClosed()) {
						result.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
				try {
					if (pstmt != null && !pstmt.isClosed()) {
						pstmt.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
				try {
					if (conn != null && !conn.isClosed()) {
						conn.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (articles.size() == 0) {
				System.out.println("게시물이 없습니다.");
				continue;
			}
			System.out.println("번호   /   제목");
			for (Article article : articles) {
				System.out.printf("%d   /    %s\n", article.id, article.title);
			}
		}

1) 실행할 sql문 작성 , 쿼리문 실행후 결과 값을 result로

			String sql = "SELECT * FROM article";
			sql += " ORDER BY id DESC;";
			System.out.println(sql);
			pstmt = conn.prepareStatement(sql);
			result = pstmt.executeQuery();

2) executeQuery() 메소드는 결과로 ResultSet을 반환,이 ResultSet으로부터 원하는 데이터를 추출

  • ResultSet에는 SELECT된 로우의 데이터 값들이 저장되어있다.

  • 데이터를 추출하는 방법은 ResultSet에서 한 행씩 이동하면서 get...()를 이용하여 원하는 필드 값을 추출하는데,
    이때 result.getString("name") 혹은 rs.getString(1)을 사용한다 (필드명을 쓰거나 칼럼 순서대로 숫자를 쓰거나)

  • ResultSet의 첫 번째 필드는 1부터 시작한다.

  • 한 행이 처리되고 다음 행으로 이동 시 next() 메소드를 사용한다.

< ResultSet >

  • ResultSet.getXXX(int columnIndex 또는 String columnName)

    • 커서가 위치한 처리행에서 원하는 컬럼값을 반환하는 메소드
    • XXX에는 컬럼값을 반환받기 위한 Java 자료형이 들어감
    • columnIndex : 검색대상의 위치값(1부터 1씩 증가되는 값 사용)
    • getXXX() : 커서의 위치에 있는 컬럼값을 반환하는 메소드
    • 모든 컬럼값은 문자열(String)로 반환받아 저장 가능
    • 따라서 컬럼의 자료형이 명확하지 않으면 일단 String으로 받아오면 됨!(필요하면 나중에 형변환)
    • 컬럼값은 하나하나씩 뽑아내야 한다 ==> '패치'라고 부름
  • ** next() : 커서가 BOF(Begin Of File)에서 시작해 EOF(End Of File)에 닿을 때까지 이동하며 커서 위치에 행이 존재하는지 판단하여, boolean값을 반환하는 메소드

			while (result.next()) {
					int id = result.getInt("id");
					String regDate = result.getString("regDate");
					String updateDate = result.getString("updateDate");
					String title = result.getString("title");
					String body = result.getString("body");
				Article article = new Article(id, regDate, updateDate, title, body);
				articles.add(article);
			}

3) JDBC 객체 연결 해제 result객체도 Statement객체와 같이 연결을 해제 시켜줘야한다.

			try {
					if (result != null && !result.isClosed()) {
						result.close();
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}

객체 Statement에서 SQL 질의 문장을 실행하는 메서드

메소드 종류반환 자료형특징
executeQuery()ResultSetSELECT와 같이 데이터베이스에 변경을 주지 않는 SQL 문장을 실행할 때 사용하며 그 결과로 ResultSet 객체를 반환
executeUpdate()intINSERT, UPDATE, DELETE와 같이 데이터베이스 구조 또는 값을 변경시키는 질의(DML), CREATE, DROP과 같은 DDL 구문을 사용할 때 사용한다 질의 수행 후 영향을 받은 행의 수를 정수로 반환한다
execute()boolean실행할 SQL문이 어떠한 종류의 것인지 모를 경우에 사용한다 결과가 ResultSet이면 true, 결과가 행의 수 이거나 없으면 false를 반환한다

2. 게시물 수정시 DB에UPDATE(수정)

1) INSERT,SELECT와 작성방식이 동일하다. 수정에서는 새로 채워질 제목과 내용을받고

		else if (cmd.startsWith("article modify ")) {
				int id = Integer.parseInt(cmd.split(" ")[2]);
				System.out.printf("== %d번 게시물 수정 ==\n", id);
				
			Connection conn = null;
			PreparedStatement pstmt = null;
			System.out.printf("새 제목 : ");
			String title = sc.nextLine();
			System.out.printf("새 내용 : ");
			String body = sc.nextLine();

2) executeUpdate() 메소드를 통해 UPDATE, 이때 수정할 로우의 id값을 조건으로 걸어줌.

			String sql = "UPDATE article";
					sql += " SET title = " + "'" + title + "'";
					sql += ", `body` = " + "'" + body + "'";
					sql += " WHERE id = " + id + ";";
					System.out.println(sql);
					pstmt = conn.prepareStatement(sql);
					pstmt.executeUpdate();

3. Main클래스의 로직을 App 클래스로 이전

기존 JAVA게시판과 같은 방식으로 Main에 모든 코드가 작성되고 있으므로 App클래스로 이전하여 리팩토링할 예정.


4 . 각 기능 내부에서 DB 연결을 하지않고 명령어 입력 직후에 한번만 연결

		while (true) {
			System.out.printf("명령어 ) ");
			String cmd = sc.nextLine().trim();
		
            Connection conn = null;

		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.out.println("예외 : 클래스가 없습니다.");
			System.out.println("프로그램을 종료합니다.");
			break;
		}

		String url = "jdbc:mysql://127.0.0.1:3306/article_manager?		useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul&useOl
            dAliasMetadataBehavior=true&zeroDateTimeNehavior=convertToNull";

		try {
			conn = DriverManager.getConnection(url, "root", "");
			int actionResult = doAction(conn, sc, cmd);

			if (actionResult == -1) {
				System.out.println("프로그램 종료");
				break;
			}
		} catch (SQLException e) {
			System.out.println("@@@@에러@@@@" + e);
		} finally {
			try {
				if (conn != null && !conn.isClosed()) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	sc.close();
}

try catch 문을 두 개로 분류

1) 첫번째 try catch문 에서 Driver 연결만 시도

  • 각각의 기능의 내부에서 드라이버 연결을 하지않고 명령어 입력시 JDBC Driver 연결

  • ClassNotFoundException 예외 처리

​ 드라이버 클래스가 없을시(드라이버 로드가 안될때)

​ break;

		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.out.println("예외 : 클래스가 없습니다.");
			System.out.println("프로그램을 종료합니다.");
			break;
		}

2) 드라이버 로드가 됬다면 두번째 try catch문 에서는 DB 연결 시도하고 doAction()에 인자로 conn,sc,cmd를 전달하여

반환값이 -1(명령어가 exit 일때, 나머지는 return 0;) 이되면 반복문 종료

			try {
			conn = DriverManager.getConnection(url, "root", "");
			int actionResult = doAction(conn, sc, cmd);

			if (actionResult == -1) {
				System.out.println("프로그램 종료");
				break;
			}

3) 아래 코드 내용은 doAction() 안의 write중 , conn객체의 종료는 doAction() 실행후 종료하게 하였으므로 각각의 pstmt와 result객체만 종료하게 함

pstmt = conn.prepareStatement(sql); 실행시 SQLException가 throws 되었으므로 try catch로 예외처리

나머지 modify,list도 이와 비슷한 방식으로 처리

	if (cmd.equals("article write")) {
		System.out.println("== 게시물 작성 ==");
		System.out.printf("제목 : ");
		String title = sc.nextLine();
		System.out.printf("내용 : ");
		String body = sc.nextLine();

		PreparedStatement pstmt = null;
		
		try {
			String sql = "INSERT INTO article";
			sql += " SET regDate = NOW()";
			sql += ",updateDate = NOW()";
			sql += ",title = '" + title + "'";
			sql += ",`body` = '" + body + "';";

			System.out.println(sql);
			
			pstmt = conn.prepareStatement(sql);				
			pstmt.executeUpdate();
		
		} catch (SQLException e) {
			System.out.println("@@@@에러@@@@: " + e);
		} finally {
			try {
				if (pstmt != null && !pstmt.isClosed()) {
					pstmt.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

0개의 댓글