20. 데이터베이스 입출력
20.1 JDBC개요
공유데이터는 데이터베이스에 저장하고 읽고 저장 수정 등을 한다.
여러 pc에서 프로그램이 공유한다면 특정pc에서 저장하는 건 불가능하다. 원격으로 db에 들어와서 관리를 하는게 필요하다.
db연결방법 데이터 가져오는 방법 데이터 저장방법등 배움
자바는 데이터베이스와 연결해서 데이터 입출력 작업을 할 수 있도록 JDBC라이브러리를 제공한다.
java database connectivity 자바데이터베이스 연결 자바 언어를 이용해 db연결을 한다.
이는 하나의 프레임 워크 라고 할 수 있다.
이 프레임워크서 제공하는 클래스 인터페이스를 통해서 사용하는 것이다.
java.sql 모듈에 있다. 여기에 java.sql javax.sql패키지가 있다. 이것들을 총칭해서 jdbc다 jdbc api다 라고 한다.
이들은 데이터베이스 관리 '소프트웨어'이다.
어떠한 것을 사용하더라도 dbms와 관련없이 사용할 수 있다 JDBC 라이브러리를 사용할 수 있다.
이걸 사용하기 위해 외부에서 가져와서 사용해야하는데 이것이 JDBC드라이버이다.
작성할때는 JDBC인터페이스를 사용하고 이걸 구현하는 객체를 JDBC드라이버이다.
이걸 누가만드냐? DBMS만드는 회사가 만든다. 예를들어 오라클은 오라클이 제공함.
우리는 JDBC인터페이스를 가지고 JDBC드라이버를 가져와서 설계하는 것이다.
java.sql javax.sql패키지가 있다. 여기에 속한 인터페이스 클래스를 통해서 데이터베이스 작업을 한다.
다가 아니지만 대표적으로 사용하는 것은 다음과 같다.
DriverManager: jdbc드라이버를 관리, 사용할수있게하는 역할
Connection 연결 인터페이스: 이런 데이터베이스 관리시스템도 하나의 서버여서 TCP를 사용한다. 연결하고 데이터를 주고받는다.
연결객체 연결자체를 객체화 한것 작업하려면 연결부터 해야함.
db와 작업을 하려면 sql로 db에 해달라 해야함.
Statement종류들은 이 sql을 실행할 수 잇는 객체있다. 인터페이스는 SQL을 DBMS에보내고 이 기술된 내용대로 데이터를 처리한다.
DBMS는 SQL만으로 부를 수 있는 것은 아님.
CallableStatment는 프로시저, 펑션등을 사용해서 데이터베이스 실행가능한 프로그램 --자바의 메소드역할임.
ResultSet 결과셋 결과가 담긴 객체, 요청-> 요청한결과 돌려줌 결과가 담긴 Set 결과를 얻어 DB에서 가져온 데이터를 읽을 때 사용
20.5 DB연결
클라이언트 프로그램을 DB와 연결하려면 해당 DBMS의 JDBC Driver가 필요하다.
또한 연결에는 4가지 정보가 필요하다
1.DBMS가 설치된 컴퓨터의 IP주소
2.DBMS가 허용하는 포트(Port) 번호
3.사용자(DB계정) 및 비밀번호
4.사용하고자하는 DB 이름
IP주소는 컴퓨터를 찾아가기 위해 Port번호는 DBMS로 연결하기위해 필요하다.
DBMS는 여러개의 DB를 관리하므로 실제로 사용할 DB이름이 필요하다.
또한 어떤 사용자인지 인증받기 위한 계정 및 비밀번호도 필요하다.
20.5.1 JDBC Driver설치
JDBC드라이버 라이브러리를 다운받아 빌드패스해야한다.
20.5.2 DB연결
클라이언트프로그램을 DB와 연결하기 위해 가장먼저해야할일은
JDBC Driver를 메모리로 로딩하는 것이다.
Class.forName() 메소드는 문자열로 주어진 JDBC Driver 클래스를 BuildPath에서 찾고, 메모리로 로딩한다
MySQL :
Class.forName("com.mysql.cj.jdbc.Driver")
자주사용했던 Oracle :
Class.forName("oracle.jdbc.OracleDriver")
이 과정에서 JDBC Driver 클래스의 static 블록이 실행되면서 DriverManager에 JDBC
Driver 객체를 등록하게 된다
class OracleDricer{
static {
Driver driver = new OracleDriver();
DrverManager.registerDriver(driver);
}이것은 메모리 블록에 로딩이되면 실행이 된다. 그래서 등록되며 사용이 가능한 것이다.
만약 드라이버가 없다면 ClassNotFoundException 예외가 발생하므로 예외처리를 해야한다.
DriverManager에 JDBC Driver가 등록되면 getConnection() 메소드로 DB와 연결을 할 수 있다
Connection conn = DriverManager.getConnection("연결 문자열", "사용자", "비밀번호");
첫 번째 매개값은 연결 문자열인데, DBMS마다 다른 형식을 가지고 있다.
연결문자열은 3가지 정보 IP번호 포트번호 DB이름이 들어가는 문자열 형식이다.
api도큐먼트를 보고 알아야한다.
Oracle : jdbc:orcale:thin:@ip주소:포트번호/DB이름
jdbc:orcale:thin:@localhost:1521/orcl
MySQL : jdbc:mysql://IP주소:포트번호/DB이름
jdbc:mysql://localhost:3306/thisisjava
localhost는 로컬에 설치된 MySQL에 연결하겠다는 의미이다.
원격 MySQL에 연결하려면 IP 주소로 기술해야 한다.
3306은 Port 번호, thisisjava는 DB명이다
연결이 성공하면 getConnection() 메소드는 Connection 객체를 리턴한다.
만약 연결이 실패하면 SQLException이 발생하므로 예외 처리를 해야 한다.
public class ConnectionExample {
public static void main(String[] args) {
Connection conn = null;
try {
// JDBC Driver등록
Class.forName("com.mysql.cj.jdbc.Driver");
// Connection객체 생성
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/thisisjava",
"chun",
"1234");
System.out.println("연결 성공");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
//연결끊기
conn.close();
System.out.println("연결끊기");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}20.6 데이터 저장
INSERT 문을 실행하는 방법을 알아보자.
테이블에 새로운 사용자 정보를 저장하는 INSERT 문은 다음과 같다.
INSERT INTO 테이블이름 (컬럼들) VALUES (값들);
sql문을 작성하면 이 문을 작성하면 클라이언트가 아닌 데이터베이스 내부에서 실행을 해야한다.
SQL문에서 문자열은 ' '로 감싸준다.
실행한다고 바로 실행되는것은 아니고 Commit까지 해줘야한다.
20.6.1 user테이블에 추가하기
자바에서 사용하려면 넣을 값들을 ?로 매개변수화해서 작성해야한다.
INSERT INTO users (userid, username, userpassword, userage, useremail)
VALUES (?, ?, ?, ?, ?);
그리고 INSERT 문을 String 타입 변수 sql에 문자열로 대입한다
String sql = new StringBuilder()
.append("IINSERT INTO users (userid, username, userpassword, userage, useremail) ")
.append("VVALUES (?, ?, ?, ?, ?)")
.toString()
또는
String sql =
"INSERT INTO users (userid, username, userpassword, userage, useremail) " +
"VALUES (?, ?, ?, ?, ?)"
매개변수화된 SQL 문을 실행하려면 PreparedStatement가 필요하다.
Connection의 prepareStatement() 메소드로부터 PreparedStatement를 얻는다.
PreparedStatement pstmt = conn.prepareStatement(sql);
?에 들어갈 값을 지정해주는데?는 순서에 따라 1번부터 번호가 부여된다.
값의 타입에 따라 Setter 메소드를 선택한 후 첫 번째에는 ? 순번, 두 번째에는 값을 지정해 준다.
pstmt.setString(1, "winter");
pstmt.setString(2, "한겨울");
pstmt.setString(3, "12345");
pstmt.setInt(4, 25);
pstmt.setString(5, "winter@mycompany.com");
값을 저장한 후 executeUpdate()메소드를 호출하면 SQL문이 실행되면서 users테이블에 1개의 행이 저장된다.
executeUpdate()가 리턴하는 값은 저장된 행 수 이다.
insert문은 1행을 넣는거니 정상적으로 실행되었을 경우 1을 리턴한다.
int rows = pstmt.executeUpdate();
PreparedStatement가 더 이상 사용하지 않을 경우에는 close()메소드를 호출해서 PreparedStatement가 사용했던 메모리를 해제한다.
pstmt.close();
// 매개변수화된 SQL 문 작성
String sql = "INSERT INTO users (userid, username, userpassword, userage, useremail) "
+ "VALUES (?, ?, ?, ?, ?)";
// PreparedStatement 얻기
PreparedStatement pstmt = conn.prepareStatement(sql);
// 값넣기
pstmt.setString(1, "winter");
pstmt.setString(2, "한겨울");
pstmt.setString(3, "12345");
pstmt.setInt(4, 25);
pstmt.setString(5, "winter@mycompany.com");
// sql문실행
int rows = pstmt.executeUpdate();
System.out.println("저장된 행수: " + rows);
// PreparedStatement 닫기
pstmt.close();20.6.2 board테이블에 추가하기
오라클에서 할때는 값을 자동 증가하는 방법이 시퀸스 밖에 없엇다.
그래서 bno자리에 시퀸스을 넣고 SQL문에서 실행시키는 방식이었다.
SEQ_BNO.NEXTVAL
MySQL은 값을 자동증가컬럼을 만들수가 있고 이미 그렇게 설정되었다.
bno int primary key auto_increment
그래서 생략하고 now()는 현재시간이다.
INSERT INTO boards (btitle, bcontent, bwriter, bdate, bfilename, bfiledata)
VALUES ('눈 오는 날', '함박눈이 내려요', 'winter', now(), 'snow.jpg', binaryData)
now()를 제외하고 매개변수화하면 다음과 같다.
String sql =
"INSERT INTO boards (btitle, bcontent, bwriter, bdate, bfilename, bfiledata) " +
"VALUES (?, ?, ?, now(), ?, ?)"
매개변수화된 INSERT 문을 실행하기 위해 다음과 같이 prepareStatement( ) 메소드로부터
PreparedStatement를 얻는데, 이전과는 다르게 두 번째 매개값이 있다
오라클 버전
PreparedStatement pstmt = conn.prepareStatement(sql,
new String[] {"bno"});
Mysql버전
PreparedStatement pstmt = conn.prepareStatement(sql,
Statement.RETURN_GENERATED_KEYS);
NSERT 문이 실행된 후 가져올 키 값으로, 자동 증가된 bno 값을 가져온다.
SQL문이 실행되기 전까지는 bno 값을 모르기 때문에 SQL 문이 실행된 후에
bno 컬럼에 실제로 저장된 값을 얻어보는 것이다
실제 몇번째 값이 저장됫는지를 보기 위한 것이다.
bfiledata 컬럼은 바이너리 타입(blob)이므로 ?에 값을 지정하려면 setBinaryStream(), setBlob(), setBytes () 메소드 중 하나를 이용해야 한다.
여기선 setBlob을 이용해서 바이트 입력 스트림을 제공한 것이다
pstmt.setString(1, "눈 오는 날");
pstmt.setString(2, "함박눈이 내려요.");
pstmt.setString(3, "winter");
pstmt.setString(4, "snow.jpg");
pstmt.setBlob(5, new FileInputStream("src/ch20/sec06/photo.jpg"));
INSERT 문을 실행하고 저장된 bno 값을 얻는 방법은 다음과 같다.
게시물 정보가 저장되었을 경우(rows가 1일 경우)
getGeneratedKeys () 메소드로 ResultSet을 얻고,
getInt() 메소드로 bno를 얻는다.
ResultSet에 대해서는 20.9절에서 자세히 설명한다.
int rows = pstmt.executeUpdate(); //SQL 문 실행
if(rows == 1) {
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next()) { //값이 있다면
int bno = rs.getInt(1); //가져온 값중 1번
}
rs.close(); //ResultSet이 사용했던 메모리 해제
}
// 매개변수화된 SQL 문 작성
String sql =
"INSERT INTO boards (btitle, bcontent, bwriter, bdate, bfilename, bfiledata) " +
"VALUES (?, ?, ?, now(), ?, ?)";
// PreparedStatement 얻기
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 값넣기
pstmt.setString(1, "눈오는날4");
pstmt.setString(2, "함박눈이 내려요4");
pstmt.setString(3, "winter");
pstmt.setString(4, "4번");
pstmt.setBlob(5, new FileInputStream("src/ch20/sec06/photo1.png"));
// sql문실행
int rows = pstmt.executeUpdate();
System.out.println("저장된 행수: " + rows);
//bno값 얻기
if (rows ==1 ) {
ResultSet rs = pstmt.getGeneratedKeys();
if (rs.next()) { //가져온 값이 있다면 실행
int bno = rs.getInt(1); //가져온 값중 1번
System.out.println("저장된 bno: " + bno);
}
rs.close();
}
// PreparedStatement 닫기
pstmt.close();20.7 데이터 수정
JDBC를 이용해서 UPDATE 문을 실행하는 방법을 알아보자.
UPDATE문은 다음과 같다.
UPDATE 테이블 SET 컬럼='변경내용', 컬럼='변경내용' WHERE 조건
동시에 여러행을 바꾸고 싶을때는 ,로 연결하고 컬럼구분자이기 때문에 마지막은 넣지 않는다.
WHERE을 작성하지 않으면 전부 바뀌어버리니 주의하자!!!
bno가 3인 게시물의 btitle, bcontent, bfilename, bfiledata를 변경하는 SQL 문은 다음과 같다
UPDATE boards SET
btitle= '눈사람',
bcontent= '눈으로 만든 사람;,
bfilename= 'snowman.jpg',
bfiledata=binaryData
WHERE bno=3
이제 이것을 매개변수화해서 스트링 타입에 넣는다.
다음은 StringBuilder를 이용해 보았다.
문자열이 합쳐졌을때 겹치지 않게 띄어쓰기 한칸씩 꼭넣어주자
String sql = new StringBuilder()
.append("update boards set")
.append("btitle = ?, ")
.append("bcontent = ?, ")
.append("bfilename = ?, ")
.append("bfiledata= ? ")
.append("where bno = ? ")
.toString();
또는
tring sql = "update boards set " + "btitle = ?, " + "bcontent = ?, " + "bfilename = ?, "
+ "bfiledata= ? " + "where bno = ? ";
매개변수화된 UPDATE문을 실행하기 위해 preparStatment()메소드로부터 preparedStatement를 얻고 ?에 해당하는 값을 지정한다.
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "눈사람");
pstmt.setString(2, "눈으로 만든 사람");
pstmt.setString(3, "snowman.jpg'");
pstmt.setBlob(4, new FileInputStgream("파일경로 및 위치"));
pstmt.setInt(5, 3);
값을 모두 지정하였다면 UPDATE문을 실행하기 위해 executeUpdate()메소드를 호출한다.
성공적으로 실행되면 수정된 행의 수가 리턴된다.
0이 리턴되면 조건에 맞는 행이 없어 수정된 내용이 없음을 의미한다.
where의 조건에 따라 달라진다. 즉 행이 없을 경우? 0이 리턴됨
>=7이런식으로 여러개를 고치면 2이상의 값이 나올수도 있음
// 매개변수화된 SQL 문 작성
String sql = "update boards set " + "btitle = ?, " + "bcontent = ?, " + "bfilename = ?, "
+ "bfiledata= ? " + "where bno = ? ";
// PreparedStatement 얻기
PreparedStatement pstmt = conn.prepareStatement(sql);
// 값넣기
pstmt.setString(1, "눈사람");
pstmt.setString(2, "눈으로 만든 사람");
pstmt.setString(3, "update");
pstmt.setBlob(4, new FileInputStream("src/ch20/sec07/photo2.png"));
pstmt.setInt(5, 3);
// sql문실행
int rows = pstmt.executeUpdate();
System.out.println("업데이트된 행수: " + rows);
// PreparedStatement 닫기
pstmt.close();20.8 데이터 삭제
SQL DELETE문은 다음과 같다.
DELETE FROM 테이블이름 WHERE 조건
삭제대상은 행이다. 컬럼하나의 값만 지울 수는 없다.
WHERE절이 빠지면 전체 행이 날아가버리니 주의하자!!!
boards 테이블에서 bwriter가 winter인 모든 게시물을 삭제하는 DELETE 문은 다음과 같다
DELETE FROM boards WHERE bwriter= 'winter';
매개변수화된 SQL문을 넣는다.
String sql = "DELETE FROM boards WHERE bwriter= ?"
매개변수화된 DELETE 문을 실행하기 위해 prepareStatement() 메소드로부터
PreparedStatement를 얻고 ?에 값을 지정한 후,
executeUpdate로 SQL 문을 실행한다. 리턴 값은 삭제된 행 수이다
String sql = "DELETE FROM boards WHERE bwriter= ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "winter");
int rows = pstmt.executeUpdate();
// SQL문
String sql = "DELETE FROM boards WHERE bwriter = ?";
// PreparedSatement객체 생성
PreparedStatement pstmt = conn.prepareStatement(sql);
// 값넣기
pstmt.setString(1, "winter");
// 실행
int rows = pstmt.executeUpdate();
System.out.println("삭제된 행 수: " + rows);
// 닫기
pstmt.close();2023.03.10 후기
오라클의 경우에 특정 컬럼의 값을 알기 위해 배열에 넣고 알아보았다. 그래서 저장된 bno의 값을 알고 번호를 알 수잇었다.
그런데 mysql문의 경우 Statement.RETURN_GENERATED_KEYS으로 작성하는데 이게 어떻게 하나의 컬럼만 지정하는지 의문이 생겼다.
찾아보니 auto_increment이 값을 식별해서 넣는 것이기 때문에 테이블 당하나만 넣을 수 있다. 그래서 값이 증가한 키는 테이블 당 단 하나만 존재하게 되는 것이다.
그래서 이것을 기준으로 값이 늘어나는 컬럼을 찾고 그 컬럼 bno의 값을 얻어올 수 있는 것이다.
'기초단계 > JAVA' 카테고리의 다른 글
| 2023.03.13 Java 복습 (0) | 2023.03.13 |
|---|---|
| 2023.03.09 Java 복습 (0) | 2023.03.10 |
| 2023.03.07 Java 복습 (0) | 2023.03.07 |
| 2023.03.03 Java 복습 (0) | 2023.03.06 |
| 2023.02.28 -2 Java 복습 (0) | 2023.02.28 |