2023.05.26
* 인터페이스를 통해 틀을 잡을 수 있음
- 클래스에서 실체화 및 구체화
* DAO
데이터베이스의 data에 접근하기 위한 객체입니다. DataBase에 접근 하기 위한 로직 & 비지니스 로직을 분리하기 위해 사용
* DTO
계층 간 데이터 교환을 하기 위해 사용하는 객체로, DTO는 로직을 가지지 않는 순수한 데이터 객체(getter & setter 만 가진 클래스)
* VO
값 오브젝트로써 값을 위해 쓰입니다. read-Only 특징(사용하는 도중에 변경 불가능하며 오직 읽기만 가능)을 가짐
DTO와 유사하지만 DTO는 setter를 가지고 있어 값이 변할 수 있다
* DTO (VO)
- DTO는 값의 변화 가능, 레코드 하나
- 데이터 클래스
-멤버변수는 직접 접근 안됨(get, set 활용)
- DAO에서 DTO를 부품으로 사용한다
- VO는 값의 변화를 줄 수 없음
● 데이터베이스 개념
레코드 = 튜플
표 = 엔티티?
* 스키마
- 데이터베이스의 구조와 제약조건에 관해 전반적인 명세를 기술한 것
- 개체의 특성을 나타내는 속성(Attribute)과 속성들의 집합으로 이루어진 개체(Entity), 개체 사이에 존재하는 관계(Relation)에 대한 정의와 이들이 유지해야 할 제약조건들을 기술한 것
* 물리적스키마 = 데이터베이스
- 실세계에 존재하는 데이터들을 어떤 형식, 구조, 배치 화면을 통해 사용자에게 보여줄 것인가
* 논리적 스키마
- 데이터 베이스의 물리적 저장구조를 정의
- 구체적으로 개념 스키마를 디스크 기억장치에 물리적으로 구현하기 위한 방법을 기술한 것
- 데이터 베이스에 넣기 전에 체계적으로 정리
* 개념적 스키마
- 데이터 베이스의 전체적인 논리적 구조
- 데이터 베이스에 실제로 어떤 데이터가 저장되었으며 데이터간의 관계는 어떻게 되는가
2023.05.25 - [백엔드/자바] - 자바 - 20 (노래 관리 프로그램 만들기)
이어서
※ 초기화 기본타입
정수 : 0
실수 : 0.0
boolean : false
문자 : '\u0000'
객체 : null
* 자바의 규칙
객체는 힙에 생성
객체는 참조변수
- 참조: 원본을 준다
참조하는 변수의 내용을 바꾸면 원본의 내용이 변경됨
● 하나의 클래스에 담기
▶ SongDAOMemoApp 클래스 만들기
▷ main() - 시작부분으로 함수 호출
- getConnection()을 호출하여 마리아디비 서버에 연결
- 처리 후 디비 닫기
public static void main(String[] args) {
// getConnection()을 호출하여 마리아디비 서버에 연결
Connection con = getConnection();
// 복잡한 비즈니스 로직 처리
// 처리 후 DB연결 닫기
// 연결된 연결객체 conn을 close 메소드로 닫기
close(con);
}
- main()이 getConnection를 호출
-> 실행결과 결과값으로 conn변수가 나옴
▷ 메소드 getConnection() - 디비와 연결해서 연결객체를 만들어 반환
public static Connection getConnection() {
// 실행되기전에 반드시 초기화(0에 가까운 값) 해야함
Connection conn = null; // 캡슐화
// 디비작업은 예외가정
try {
String db_driver_name = "org.mariadb.jdbc.Driver";
// 해당 이름의 라이브러리가 있는지 검사
// 라이브러리가 있으면 메모리로 실행코드 로딩
Class.forName(db_driver_name);
// DB 드라이버가 있다면 디비서버로 연결 | 없으면 SQL 예외처리
// 프로티콜 구분기호는 항상 ://
// 127.0.0.1은 로컬네트워크 주소
String jdbc_url = "jdbc:mariadb://localhost:3306/muse";
String user = "root";
String passwd = "mariadb";
conn = DriverManager.getConnection(jdbc_url, user, passwd);
} catch(SQLException se) {
} catch(Exception e) {
// 배우는 중이므로 어떤 에러가 나는지 확인
e.printStackTrace();
}
return conn; // 참조변수라서 객체의 주소를 넘김
}
- getConnection은 Connection의 conn이라는 변수를 가짐 -> mariadb와 연결
- return conn; -> 컨넥션객체의 주소를 변수이름(conn)으로 리턴
* 메인의 참조변수와 메소드(메인 밖)의 참조변수가 다른 이름을 가져도 같은 힙의 주소를 가르키면
매소드가 종료되어도 메인이 가르키고 있기 때문에 힙의 객체는 사라지지 않는다 메인까지 종료되면 가비지콜랙터에 의해 사라진다
▷ 자원반납 - 닫기
public static void close(Statement stmt, Connection conn) {
// stmt 닫기
try {
stmt.close();
} catch (SQLException se) {
se.printStackTrace();
}
// conn 닫기
try {
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void close(Connection conn) {
try {
conn.close();
} catch (SQLException se) {
se.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException se) {
}
}
}
▷ selectSongOne() : 레코드 1개 가져오기
- try 위치
stmt 선언 전에 하여야 stmt를 내부에서 사용할 수 있음
-> 지역변수
- mariadb로 Select * from song limit 1; 문을 전송하여 결과레코드를 가져옴
public static void selectSongOne(Connection conn) {
Statement stmt = null;
ResultSet rs = null; // 결과를 가지고 있는 2차원 배열
try {
String sql = "SELECT * FROM song limit 1;";
stmt = conn.createStatement(); // factory pattern
rs = stmt.executeQuery(sql);
if (rs.next()) { // 값을 하나만 리턴하는 경우(limit 1에 의해 보장)
// 레코드가 있다면
int songId = rs.getInt("song_id");
String songName = rs.getString("song_name");
String songContent = rs.getString("song_content");
String singer = rs.getString("singer");
p("song_id = " + songId);
p("\nsong_name = " + songName);
p("\nsong_content = " + songContent);
p("\nsinger = " + singer);
pl("");
} else {
// 자료가 없다면
pl("찾으시는 자료가 없습니다.");
}
} catch(SQLException se) {
se.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
* rs.next()
- read only cursor
-> 메모리 방이 미리 만들어져야해서 배열 활용
rs의 데이터는 리턴값을 가지면 안되고
반환을 하고 메모리에 복사해야함
사용 완료하면 자원 반납
- 실행(main)
public static void main(String[] args) {
// getConnection()을 호출하여 마리아디비 서버에 연결
Connection con = getConnection();
// 실행
selectSongOne(con);
}
▷ selectSong() : 전체값 가져오기
- sql 외부에서 가져오기 (main내부에 작성 | 클래스 변수로 작성)
-> 매개변수 2개 필요
- 마리아디비 song테이블에 자료가져오기(풀쿼리이름)
-> SELECT * FROM `muse`.`song`
-> 현재는 JDBC_URL에 디비명이 들어가있으므로(`muse`를 가르킴) 짧은 이름으로 해도 된다
// public static String sql = "SELECT * FROM `muse`.`song`;"; // 클래스변수
public static void selectSong(Connection con, String selectSQL) {
// SQL명령을 실행할 stmt 객체 필요
Statement stmt = null;
ResultSet rs = null; // 데이터베이스와 연결되어있음
try {
stmt = con.createStatement();
rs = stmt.executeQuery(selectSQL);
// 노래가 있는 경우
if (rs.next()) { // 데이터가 있는지 확인
do { // 값이 여러개가 오기 때문에 반복문 사용(do-while)
int songId = rs.getInt("song_id");
String songName = rs.getString("song_name");
String songContent = rs.getString("song_content");
String singer = rs.getString("singer");
pl("");
p("song_id = " + songId);
p("\nsong_name = " + songName);
p("\nsong_content = " + songContent);
p("\nsinger = " + singer);
} while(rs.next());
} else {
pl("등록된 노래가 없습니다.");
}
} catch(SQLException se) {
se.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
- 실행(main)
public static void main(String[] args) {
// getConnection()을 호출하여 마리아디비 서버에 연결
Connection con = getConnection();
// 복잡한 비즈니스 로직 처리
String sql = "SELECT * FROM `muse`.`song`;"; // 외부에서 sql쿼리 실행(지역변수)
selectSong(con, sql);
* arraylist : 배열이 필요할때 사용
▷ insert / update / delete 실행
※ insert into - song 데이터 추가하기
public static void insertSong(Connection con, String insertSQL) {
Statement stmt = null;
try {
stmt = con.createStatement(); // factory pattern
int insertCount = stmt.executeUpdate(insertSQL);
if(insertCount > 0) {
pl("" + insertCount + "자료를 추가했습니다.");
}
} catch(SQLException se) {
se.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
※ update - song 수정
public static void updateSong(Connection con, String updateSQL) {
Statement stmt = null;
try {
stmt = con.createStatement();
int updateCount = stmt.executeUpdate(updateSQL);
if(updateCount > 0) {
pl("" + updateCount + "자료를 수정했습니다.");
}
} catch(SQLException se) {
se.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
※ delete - song 삭제
public static void deleteSong(Connection con, String deleteSQL) {
Statement stmt = null;
try {
stmt = con.createStatement();
int deleteCount = stmt.executeUpdate(deleteSQL);
if(deleteCount > 0) {
pl("" + deleteCount + "자료를 삭제했습니다.");
}
} catch(SQLException se) {
se.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
- 실행(main)
public static void main(String[] args) {
// getConnection()을 호출하여 마리아디비 서버에 연결
Connection con = getConnection();
// insert 추가
String insertSQL = """
INSERT INTO song
(song_id, song_name, song_content, singer)
VALUES
(200, '좋은 날', '', '아이유'); """;
// 호출(실행)
insertSong(con, insertSQL);
// update 수정
String updateSQL = """
UPDATE
`muse`.`song`
SET
song_name = '아이유의 좋은 날',
song_content = '좋은 날 2023ver',
singer = 'IU'
WHERE singer = '아이유';
""";
// 호출
updateSong(con, updateSQL);
// delete 삭제
String deleteSQL = """
DELETE FROM song
WHERE singer = 'IU';
""";
// 호출
deleteSong(con, deleteSQL);
// 처리 후 DB연결 닫기
// 연결된 연결객체 conn을 close 메소드로 닫기
close(con);
}
● SongDAODemoApp 분리
* 데이터 관련끼리 묶기
- package : song.model 만들기
- class : SongDAO, SongDTO 만들기
▷ SongDAO
- 마리아디비의 song테이블과 JDBC로 SQL실행 관리 클래스
- 하나의 클래스에 합친것과 달리 분리한 클래스는 내부에 변수를 선언해주어서
- 매개변수를 넘겨줄 필요 없음 불필요한 변수선언을 하지 않아도 됨
* SongDAO에 SongDAODemoApp 의
- 컨넥션 객체 옮기기
package song.model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SongDAO {
// 멤버변수(전역변수)
Connection conn;
Statement stmt;
ResultSet rs;
// 데이터베이스 테이블의 레코드를 저장
SongDTO songDTO;
// 생성자
public SongDAO() {
this.conn = null;
this.stmt = null;
this.rs = null;
}
// 기능 메소드
// 디비와 연결해서 연결객체를 만들어 반환하는 메소드
public Connection getConnection() {
// 실행되기전에 반드시 초기화(0에 가까운 값) 해야함
Connection conn = null; // 캡슐화
// 디비작업은 예외가정
try {
String db_driver_name = "org.mariadb.jdbc.Driver";
// 해당 이름의 라이브러리가 있는지 검사
// 라이브러리가 있으면 메모리로 실행코드 로딩
Class.forName(db_driver_name);
// DB 드라이버가 있다면 디비서버로 연결 | 없으면 SQL 예외처리
// 프로티콜 구분기호는 항상 ://
// 127.0.0.1은 로컬네트워크 주소
String jdbc_url = "jdbc:mariadb://localhost:3306/muse";
String user = "root";
String passwd = "mariadb";
conn = DriverManager.getConnection(jdbc_url, user, passwd);
} catch(SQLException se) {
} catch(Exception e) {
// 배우는 중이므로 어떤 에러가 나는지 확인
e.printStackTrace();
}
return conn; // 참조변수라서 객체의 주소를 넘김
}
}
- close 옮기기
public class SongDAO {
// 멤버변수(전역변수)
Connection conn;
Statement stmt;
ResultSet rs;
// 데이터베이스 테이블의 레코드를 저장
SongDTO songDTO;
// 생성자
public SongDAO() {
this.conn = null;
this.stmt = null;
this.rs = null;
}
// 기능 메소드
public void close(ResultSet rs, Statement stmt, Connection conn) {
// rs 닫기
try {
rs.close();
} catch (SQLException se) {
se.printStackTrace();
}
// stmt 닫기
try {
stmt.close();
} catch (SQLException se) {
se.printStackTrace();
}
// conn 닫기
try {
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public void close(Statement stmt, Connection conn) {
// stmt 닫기
try {
stmt.close();
} catch (SQLException se) {
se.printStackTrace();
}
// conn 닫기
try {
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public void close(Connection conn) {
try {
conn.close();
} catch (SQLException se) {
se.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException se) {
}
}
}
}
▷ SongDTO
- SongDAO에서 사용하는 마리아디비의 song테이블의 데이터(열의 구조) 클래스 - 레코드와 다름
- 자바 데이터 클래스와 song테이블 사이의 1 : 1 관련성을 연결해주는 클래스 = 엔티티(Entity) 클래스
- 엔티티 클래스는 테이블의 열의 구조와 비슷하게 하면 됨
- 이름 규칙은 자바는 카멜, 데이터베이스는 스네이크 표기법을 권장
- 멤버변수는 private 처리하기
package song.model;
public class SongDTO {
// 변수는 외부 접근 불허
private int songId;
private String songName;
private String songContent;
private String singer;
// 생성자
public SongDTO() { // 기본생성자
}
public SongDTO(
int songId,
String songName,
String songContent,
String singer) {
setAllMember(songId, songName, songContent, singer);
}
// 외부 접근 허용하기 위한 getter/setter메소드 생성(인가)
public int getSongId() {
return this.songId;
}
public String getSongName() {
return this.songName;
}
public String getSongContent() {
return this.songContent;
}
public String getSinger() {
return this.singer;
}
public void setSongId(int songId) {
this.songId = songId;
}
public void setSongName(String songName) {
this.songName = songName;
}
public void setSongContent(String songContent) {
this.songContent = songContent;
}
public void setSinger(String singer) {
this.singer = singer;
}
// 모든 멤버를 한번에 추가하는 메소드 setAllMember()
public void setAllMember(
int songId,
String songName,
String songContent,
String singer ) {
this.songId = songId;
this.songName = songName;
this.songContent = songContent;
this.singer = singer;
}
@Override
public String toString() {
return " songId=" + songId + ", "
+ "songName=" + songName
+ ", songContent=" + songContent
+ ", singer=" + singer;
}
@Override // 새로만들거나 개선
public boolean equals(Object obj) {
SongDTO other = (SongDTO)obj; // 다운캐스팅
// 모든 내용이 일치하게 하고 싶으니까 논리곱 && 활용
// 정수형(int)은 == 사용 | String은 equals() 사용
if ((this.songId == other.songId)&&
(this.songName.equals(other.songName)) &&
(this.songContent.equals(other.songContent)) &&
(this.singer.equals(other.singer))) {
// this == other
return true;
} else {
// SongDTO가 다른 대상이다
return false;
}
}
}
* 테이블은 열이 만드는 것
- 레코드가 만드는 것이 아님
** 의문점
1. SongDAODemoApp
Q sql 외부에서 가져올때 외부로 빼야하는 것은 이해가 되는데 위치를 메인에서 선언해야하는 이유가 ?
A그냥 클래스 변수로 선언해도 문제 없음
Q 하나는 내부 하나는 외부에서 가져오기 가능한가
A 불가능, 내부에서 가져올거면 매개변수로 적을필요 없음
* 보안
인증이란?
- 유저가 누구인지 확인하는 절차, 회원가입하고 로그인 하는 것.
인가란?
- 유저에 대한 권한을 허락하는 것.
-> 동시에 진행되어야함
* DAO는 db로 접속, 질의, 레코드저장, 레코드를 저장할 메모리장소(DTO) 능력이 생김
- 레코드가 여러개 들어올 경우 저장하기 위한 장소(테이블)가 필요(DTO는 하나만 가능)
- 테이블 생성
1) Array 배열활용(내가 정의한 범위만큼 활용)
-> 넉넉하게 배열을 정하거나, 매번 수정이 필요 효율성이 떨어짐
2) ArrayList(데이터에 따라 사이즈가 변함) - 테이블의 역할을 함
* list map set의 실제구현
arraylist
hashmap
hashset
▷ SongDAOExamApp 만들기 (미완성)
1. 데이터베이스 관리객체를 이용하여 db관련 처리를 할 것.
SongDAO songDAO = new SongDAO();
2. songDAO객체가 마리아디비 서버로 연결해야함
songDAO.getConnection();
3. 명령객체를 생성해야함(stmt객체-insert, update등 에서 생성됨)
명령객체를 이용해서 원하는 SQL처리를 하면 됨
명령처리 결과로 ResultSet을 반환하면 화면에 보여줌(view 기능)
.
4. 명령수행이 마무리되었으면 연결객체 종료
songDAO객체는 디비와 연결을 정리함
프로그램이 종료된다.
songDAO.close();
* 상속
is 관계
- 부모 클래스(일반적인 개념)를 자식 클래스(구체적인 개념)에서 구체화할 때, 상속을 사용
has 관계
- A와 B는 사용관계, 포함관계에 있을 때, 생성자 사용
- 부모객체는 B에 종속된다
'백엔드 > 자바' 카테고리의 다른 글
자바 - 23 (0) | 2023.06.01 |
---|---|
자바 - 22 (List - 리스트) (0) | 2023.05.31 |
자바 - 20 (노래 관리 프로그램 만들기) (0) | 2023.05.25 |
자바 - 19 (데이터베이스 연결) (0) | 2023.05.25 |
자바 - 18 (데이터베이스 연결) (0) | 2023.05.22 |