배운 점
JDBC 라이브러리
자바는 데이터베이스(DB)와 연결해서 데이터 입출력 작업을 할 수 있도록 JDBC 라이브러리
(java.sql 패키지)를 제공
JDBC는 데이터베이스 관리시스템(DBMS)의 종류와 상관없이 동일하게 사용할 수 있는 클래스와 인터페이스로 구성
구현한 클래스를 jar 파일형태로 드라이버 만들어서 제공
멀티탭처럼 공기청정기, 충전기 꼽아 사용한다.
Driver Manager(드라이버 관리자): JDBC는 드라이버 관리자를 사용하여 데이터베이스 드라이버의 목록을 관리합니다. 드라이버 관리자는 적절한 드라이버를 사용하여 데이터베이스에 연결하는 역할을 합니다.
JDBC 드라이버: JDBC 드라이버는 Java 어플리케이션과 특정 데이터베이스 간의 상호 작용을 가능하게 하는 플랫폼별 구현입니다. JDBC 드라이버에는 Type 1 (JDBC-ODBC 브리지), Type 2 (Native-API 드라이버), Type 3 (네트워크 프로토콜 드라이버), Type 4 (Thin 드라이버 또는 직접 데이터베이스 드라이버)와 같이 네 가지 유형이 있습니다.
Connection(연결): Connection 인터페이스는 데이터베이스에 대한 연결을 나타냅니다. 이를 사용하여 연결을 설정하고 명령문을 만들며 트랜잭션을 관리할 수 있습니다.
Statement(명령문): Statement 인터페이스는 데이터베이스에서 SQL 쿼리를 실행하기 위해 사용됩니다. Statement (일반 목적의 쿼리에 사용), PreparedStatement (매개변수를 사용한 미리 컴파일된 SQL 문에 사용), CallableStatement (저장 프로시저에 사용)과 같이 세 가지 유형이 있습니다.
ResultSet(결과 집합): ResultSet 인터페이스는 쿼리의 결과를 나타내며 결과 집합에서 데이터를 검색하기 위한 메서드를 제공합니다.
PreparedStatement(미리 컴파일된 명령문): 이는 다양한 매개변수로 재사용할 수 있는 미리 컴파일된 SQL 명령문입니다. SQL 문을 각 실행마다 컴파일하는 오버헤드를 줄여 성능을 향상시키는 데 도움이 됩니다.
CallableStatement(호출 가능한 명령문): 이는 데이터베이스의 저장 프로시저를 호출하기 위해 사용됩니다.
JDBC Driver
JDBC 인터페이스를 구현한 것으로, DBMS마다 별도로 다운로드받아 사용
DriverManager 클래스: JDBC Driver를 관리하며 DB와 연결해서 Connection 구현 객체를 생성
Connection 인터페이스: Statement, PreparedStatement, CallableStatement 구현 객체를 생성하며, 트랜잭션 처리 및 DB 연결을 끊을 때 사용
Statement 인터페이스: SQL의 DDL과 DML 실행 시 사용
PreparedStatement: SQL의 DDL, DML 문 실행 시 사용. 매개변수화된 SQL 문을 써 편리성과 보안성 유리
CallableStatement: DB에 저장된 프로시저와 함수를 호출
ResultSet: DB에서 가져온 데이터를 읽음
커넥션 객체를 생성한다. -> 이제부터 데이터가 왔다갔다 통신할 수 있어요
커넥션 통신하고 싶은 서버한테 요청, (아이디 패스워드 데이터베이스 스키마)
쿼리문을 CRUD 담아서 보낸다.
드라이버 매니저 - 커넥션 - sql관련된 쿼리문 실어서 담을 패키지(prepared statement 통해서) 나 이러이러한 자료가 필요해,삭제해줘,입력해줘,생성해줘 ~
DB연결
1.DriverManager 클래스 : Connection 객체 생성(id,pw,스키마정보)
2.Connection 객체==> 쿼리문을 작성하여 ==> Statement, PreparedStatement ==> DBMS로 보내기 ==> 처리 결과 확인(Select 결과는 ResultSet 객체에 저장한다.)
==> Connection, stmt, psmt 자원 해제
Class.forName("com.mysql.cj.jdbc.Driver");
//밴더에서 정한 패키지이름
Connection conn = DriverManager.getConnection("연결 문자열","사용자","비밀번호");
연결 예시:
public static void main(String[] args) {
Connection conn = null;
try {
//1. JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 연결하기
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul", "root", "1111");
// 세계 협정시 GNT로 요청하면 오류 발생
System.out.println("Connection OK!!" + conn); // com.mysql.cj.jdbc.ConnectionImpl@59662a0b 이객체에 통신객체 담는다
//connection 얻어오겠다
System.out.println("연결 성공");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//3. 연결 끊기
conn.close();
System.out.println("연결 끊기");
} catch (SQLException e) {}
}
}
}
JDBC url 파라미터에 serverTimezone이 명시되있지 않을 경우:
현재 어플리케이션의 Timezone으로 Connection이 맺어진다.
JDBC url 파라미터에 serverTimezone이 명시되있을 경우:
serverTimezone의 값으로 Timezone 인스턴스를 생성하여 생성된 Timezone으로 Connection이 맺어진다.
드라이버 찾는 경로:
package javaStudy.jdbcconnect;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UserInsertExample {
public static void main(String[] args) {
Connection conn = null;
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//클래스를 이름으로 찾겠다.
System.out.println("driver ok!");
//연결하기
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul", "root", "1111");
//매개변수화된 SQL문 작성
String sql = "INSERT INTO users (userid,username,userpassword,userage,useremail)"+
"values(?,?,?,?,?)";
//PreparedStatement 얻기 및 값 지정
//작성한 쿼리문 실어주기
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1,"ssg");
pstmt.setString(2,"신세계");
pstmt.setString(3,"1234");
pstmt.setInt(4,30);
pstmt.setString(5,"ssg@gmail.com");
//SQL문 실행
int rows = pstmt.executeUpdate();
//메서드는 정수 값을 반환하며, 이 값은 영향을 받은 행의 수입니다. 즉, 몇 개의 레코드가 업데이트, 삽입 또는 삭제되었는지를 나타냅니다
System.out.println("저장된 행 수: " + rows);
//PreparedStatement 닫기
pstmt.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close(); // 연결 끊어 줄 것
} catch (SQLException e) {}
}
}
}
}
executeUpdate() :
INSERT 문 실행: 데이터베이스에 새로운 레코드를 추가할 때 사용됩니다.
UPDATE 문 실행: 이미 존재하는 레코드의 값을 업데이트할 때 사용됩니다.
DELETE 문 실행: 데이터베이스에서 레코드를 삭제할 때 사용됩니다.
메서드는 정수 값을 반환하며, 이 값은 영향을 받은 행의 수입니다. 즉, 몇 개의 레코드가 업데이트, 삽입 또는 삭제되었는지를 나타냅니다
package javaStudy.jdbcconnect;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class BoardInsertExample {
public static void main(String[] args) {
Connection conn = null;
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//연결하기
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul",
"root",
"1111"
);
//매개변수화된 SQL문 작성
// auto increment는 가만 놨두셈 title부터 넣으셈
// String sql = "INSERT INTO boards"+
// "(btitle,bcontent,bwriter,bdate,bfilename,bfiledata)"
// +"values ('오늘은 JDBC 학습','MYSQL JDBC 라이브러리 학습중','ssg',now(),'snow.jpg',binaryData)";
String sql = "INSERT INTO boards (btitle,bcontent,bwriter,bdate,bfilename,bfiledata)"
+ "values(?,?,?,now(),?,?)";
//PreparedStatement 얻기 및 값 지정
PreparedStatement pstmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
//RETURN_GENERATED_KEYS : 자동으로 생성된 키(Generated Key)를 얻고자 할 때 사용
pstmt.setString(1,"오늘은 JDBC 학습");
pstmt.setString(2,"MYSQL JDBC 라이브러리 학습중");
pstmt.setString(3,"ssg");
pstmt.setString(4,"snow.jpg");
pstmt.setBlob(5,new FileInputStream("snow.jpg"));
//BLOB(Binary Large Object) 데이터를 쿼리에 바인딩할 때 사용
//SQL문 실행
int rows = pstmt.executeUpdate();
System.out.println("저장된 행 수: " + rows);
//bno 값 얻기
if(rows == 1){
ResultSet rs = pstmt.getGeneratedKeys(); // bno 컬럼값을 리턴받는다.
if(rs.next()){
int bno = rs.getInt(1);
System.out.println("bno:"+bno);
}
rs.close();
}
//PreparedStatement 닫기
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close();
} catch (SQLException e) {}
}
}
}
}
Statement.RETURN_GENERATED_KEYS :
Statement 또는 PreparedStatement를 생성할 때 사용됩니다. 이 상수를 사용하면 데이터베이스에서 자동으로 생성된 키(예: 자동 증가하는 기본 키)를 검색할 수 있습니다.
일반적으로 데이터베이스에서 행을 삽입할 때, 자동으로 생성된 키(Generated Key)를 얻고자 할 때 사용
UPDATE 예시:
public static void main(String[] args) {
Connection conn = null;
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//클래스를 이름으로 찾겠다.
System.out.println("driver ok!");
//연결하기
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul", "root", "1111");
//매개변수화된 SQL문 작성
String sql = new StringBuilder().append("UPDATE users SET ")
.append("userpassword=?")
.append("where userid=?")
.toString();
//PreparedStatement 얻기 및 값 지정
PreparedStatement pstmt = conn.prepareStatement(sql);
//작성한 쿼리문 실어주기
pstmt.setString(1,"12345");
pstmt.setString(2,"ssg");
//SQL문 실행
int rows = pstmt.executeUpdate();
//메서드는 정수 값을 반환하며, 이 값은 영향을 받은 행의 수입니다. 즉, 몇 개의 레코드가 업데이트, 삽입 또는 삭제되었는지를 나타냅니다
System.out.println("저장된 행 수: " + rows);
//PreparedStatement 닫기
pstmt.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close(); // 연결 끊어 줄 것
} catch (SQLException e) {}
}
}
}
삭제 예시:
public static void main(String[] args) {
Connection conn = null;
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//연결하기
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul",
"root",
"1111"
);
String sql = new StringBuilder().append("DELETE FROM boards WHERE bno=? ").toString();
//PreparedStatement 얻기 및 값 지정
PreparedStatement pstmt = conn.prepareStatement(sql);
//작성한 쿼리문 실어주기
pstmt.setString(1,"1");
//SQL문 실행
int rows = pstmt.executeUpdate();
System.out.println("삭제된 행 수: " + rows);
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close();
} catch (SQLException e) {}
}
}
}
ResultSet 구조
SELECT 문에 기술된 컬럼으로 구성된 행(row)의 집합
SELECT userid, username, userage FROM users
커서 cursor가 있는 행의 데이터만 읽을 수 있음
first행을 읽으려면 next() 메소드로 커서 이동
boolean result = rs.next();
데이터 행 읽기
커서가 있는 데이터 행에서 각 컬럼의 값은 Getter 메소드로 읽음
SELECT 문에 연산식이나 함수 호출이 포함되어 있다면 컬럼 이름 대신에 컬럼 순번으로 읽어야 함
컬럼으로 가져오는거 권장 , 정확하니깐!
사용자 정보 읽기
사용자 정보를 가져오는 SELECT 문. prepareStatement() 메소드로부터 PreparedStatement를 얻고, ?에 값을 지정
executeQuery() 메소드로 SELECT 문을 실행해서 ResultSet을 얻음. ▪ if 문을 이용해서 next() 메소드가 true를 리턴할 경우에는 데이터 행을 User 객체에 저장하고 출력
게시물 정보 읽기
boards 테이블에서 bwriter가 winter인 게시물의 정보를 가져오기
bwriter가 winter인 게시물 정보를 가져오는 SELECT 문. prepareStatement() 메소드로부터 PreparedStatement를 얻고, ?에 값을 지정
executeQuery() 메소드로 SELECT 문을 실행해서 ResultSet을 얻음
while 문을 이용해서 next() 메소드가 false를 리턴할 때까지 반복해서 데이터 행을 Board 객체에 저장하고 출력한다
Blob 객체에 저장된 바이너리 데이터를 얻기 위해서는 입력 스트림 또는 배열을 얻어냄
Blob 객체에서 InputStream을 얻고, 읽은 바이트를 파일로 저장
User class
public class User {
private String userid;
private String userName;
private String userPassword;
private int userAge;
private String userEmail;
}
public static void main(String[] args) {
Connection conn = null;
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//클래스를 이름으로 찾겠다.
System.out.println("driver ok!");
//연결하기
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul", "root", "1111");
//매개변수화된 SQL문 작성
String sql = "SELECT userid,username,userpassword,userage,useremail "+
"FROM users "+
"WHERE userid = ? ";
//PreparedStatement 얻기 및 값 지정
//작성한 쿼리문 실어주기
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1,"ssg");
//SQL문 실행
ResultSet rs = pstmt.executeQuery();
if(rs.next()){
User user = new User();
user.setUserid(rs.getString("userid"));
user.setUserPassword(rs.getString("userpassword"));
user.setUserName(rs.getString("username"));
user.setUserAge(rs.getInt("userage"));
user.setUserEmail(rs.getString("useremail"));
System.out.println(user);
}else{
System.out.println("사용자가 존재하지 않습니다.");
}
rs.close();
//PreparedStatement 닫기
pstmt.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close(); // 연결 끊어 줄 것
} catch (SQLException e) {}
}
}
}
MultiSelect 여러 튜플 검색
Board class
public class Board {
private int bno;
private String btitle;
private String bcontent;
private String bwriter;
private Date bdate;
private String bfilename;
private Blob bfiledata;
.
.
.
SELECT
Board객체 리스트를 만든다.
while(rs.next())를 통해 한 행 씩가져와서 new Board한다.
add.(Board) 한다.
package javaStudy.jdbcconnect;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.*;
import java.util.ArrayList;
public class BoardMultiSelectExample {
public static void main(String[] args) {
Connection conn = null;
ArrayList<Board> boardList = new ArrayList<Board>();
// 보드 리스트 생성
try {
//JDBC Driver 등록
Class.forName("com.mysql.cj.jdbc.Driver");
//연결하기
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/sqldb?serverTimezone=Asia/Seoul",
"root",
"1111"
);
String sql = new StringBuilder().append("SELECT * FROM boards").toString();
//PreparedStatement 얻기 및 값 지정
PreparedStatement pstmt = conn.prepareStatement(sql);
//SQL문 실행
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
//rs 객체의 한 행(row)를 읽어서 Board 객체에 저장한다.
Board board = new Board();
board.setBno(rs.getInt("bno"));
board.setBtitle(rs.getString("btitle"));
board.setBcontent(rs.getString("bcontent"));
board.setBwriter(rs.getString("bwriter"));
board.setBfilename(rs.getString("bfilename"));
board.setBdate(rs.getDate("bdate"));
board.setBfiledata(rs.getBlob("bfiledata"));
boardList.add(board);
//파일저장
Blob blob = board.getBfiledata();
if(blob != null){
InputStream is = blob.getBinaryStream();
OutputStream os = new FileOutputStream(board.getBfilename());
is.transferTo(os);
os.flush();
os.close();
is.close();
}
}
for(Board board : boardList) System.out.println(board.toString());
rs.close();
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(conn != null) {
try {
//연결 끊기
conn.close();
} catch (SQLException e) {}
}
}
}
}
회고
오늘 내용은 쉬웠다. 졸작할때, 과제할 때 javascript에서 mysql 연결해서 사용했었다.
형식은 좀 다르지만 비슷하고 간단했다.
정해진 틀에 원하는 쿼리만 넣어서 사용하면된다. 여러 튜플을 받을때만 리스트로 받는부분 신경쓴다.
게시판 과제 나왔는데 기존에 짜 놨던거에 디비 연결만 하면 될 것같다.
'신세게 - Java 공부' 카테고리의 다른 글
10주차 배운점 - 리눅스 명령어, 네트워크 (3) | 2024.10.07 |
---|---|
10주차 배운점 느낀점 - Linux, 명령어 (10) | 2024.10.07 |
9주차 배운점 느낀점 - 네트워크, IP, Port (4) | 2024.10.07 |
9주차 배운점 느낀점 - 입출력스트림, 보조스트림, 직렬화 역직렬화 (3) | 2024.10.07 |
9주차 배운점 느낀점 - 이상현상, 함수 종속성, 정규화 (3) | 2024.10.07 |