JDBC 란?

  • 자바와 데이터베이스를 연결하여 입출력 작업할 수 있는 라이브러리(java.sql 패키지)
  • JDBC에 포함된 클래스와 인터페이스 연관관계

주요 클래스 및 인터페이스

DriverManager (class)

  • JDBC Driver를 관리
  • DB와 연결해서 Connection 구현 객체 생성

Connection (interface)

  • Statement, PreparedStatement, CallableStatement 구현 객체 생성
  • 트랜잭션(Transaction) 처리 및 DB 연결을 끊을 때 사용한다.

Statement (interface)

  • SQL의 DDL(Data Definition Language)과 DML(Data Manipulation Language)을 실행할 때 사용
  • 주로 변경되지 않는 정적 SQL 문을 실행할 때 사용

PreparedStatement

  • Statement와 동일하게 SQL의 DDL, DML 문을 실행할 때 사용
  • 차이점은 매개변수화된 SQL 문을 사용할 수 있기 때문에 편리성과 보안성이 좋음(동적 SQL도 사용 가능)
  • Statement 보다는 PreparedStatement를 주로 사용한다.

CallableStatement

  • DB에 저장되어 있는 프로시저와 함수를 호출할 때 사용(잘 안씀)

ResultSet

  • DB에서 가져온 데이터를 읽을 때 사용

JDBC 환경 설정

1. DB연결

  • JDBS Driver: IP주소를 받아 포트번호로 연결
    1. DBMS가 설치된 컴퓨터의 IP 주소
    2. DBMS가 허용하는 포트(Port) 번호
    3. 사용자(DB 계정) 및 비밀번호
    4. 사용하고자 하는 DB 이름

1. JDBC 드라이버 다운

  1. MySQL 드라이버 다운로드 > 아카이브 선택 > platform idnependent > zip 다운

  1. 이클립스에 jar 파일 추가

  • 📌 3번이 아닌 Add External JARS 를 선택해야한다

2. 자바와 mysql 연결

  • 클라이언트 프로그램을 DB와 연결하기 위해 JDBC Driver를 메모리로 로딩
  • 연결 성공 시 getConnection() 메소드는 Connection 객체 리턴
  • 연결 실패 시 SQLException이 발생하므로 예외 처리해야 한다
  • JDBC를 넣은 패키지에서 클래스와 연결

    package test; -- JDBC넣은 패키지
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    
    public class Mysql {
    	public static Connection get() { -- main()함수 대신 Connertion
    		Connection con = null; -- import java.sql.Connection;
    
    		try {
    			String id="root"; -- mySQL id
    			String pw="1234";
    			String url="jdbc:mysql:-- localhost:3306/ksj"; -- mySQL의 로컬호스트명, 프로젝트명
    
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			--  Class 클래스로 mysql 드라이버를 로딩하는 코드 →DriverManager에 등록됨
    
    			con = DriverManager.getConnection(url, id, pw); -- import java.sql.DriverManager;
    			-- Connerchion객체를 얻음
    			-- con은 실제로 데이터베이스dhk 연결하여 작업을 수핼할 수 있는 통로를 작용하는
    			-- 중요한 객체 변수로 사용됨!
    
    			System.out.println("데이터베이스에 연결됨");
    		}catch(Exception e) {
    			System.out.println("로딩실패");
    		}
    		return con;
    	}
    }
    

2. SQL 데이터 가져오기

  • JDBC Driver와 연결된 클래스(Mysql)의 함수를 호출해서 사용
  • 데이터 가져오기는 ResultSet 인터페이스에 있는 .get_() 함수 이용(getString, .getint 등)
  • 데이터를 삽입하고 싶으면 ResultSet 인터페이스에 있는 .Set_()함수 사용
  • 필수적으로 가져와야하는 객체

    • Connection 인터페이스
    • PreparedStatement 인터페이스
    • ResultSet 인터페이스
    • 작성순서
    -- 인터페이스 객체 생성
    Connection con = null;         -- DB연결
    PreparedStatement psmt = null; -- sql문 객체
    ResultSet rs = null;           -- 결과값 저장
    			-- ResultSet 객체안만들면 후에 psmt.setString(열번호,데이터); 식으로 넣기가능
    
    try{
    	--	1. DB연결
    	con = Mysql.get();
    	-- 클래스로 연결 안해놨으면 직접 연결
    	/*
    	Class.forName("com.mysql.cj.jdbc.Driver");
    	con = DriverManager.getConnection(
    		"jdbc:mysql://localhost:3306/ksj", "root", "1234");
    			    ↑  URL                        ↑ID     ↑PW
    	*/
    
    	-- 2. 매개변수화된 SQL문 작성
    	String sql = ""+"INSERT INTO 테이블명(열1,열2)" + "VALUES(?,?)";
    																-- ↑지정한 열에        ↑4.값을 넣겠다
    	-- 3.결과값 저장
    	psmt = con.prepareStatement(que);
    	-- rs = psmt.executeQuery();로 쿼리실행 결과를 rs에 저장할 수도 있음
    				-- 데이터 가져오는 select → executeQuery();
    				-- DML(insert, update, delete) → executeUpdate();
    
    	-- 4. 값 지정
    	psmt.setString(1, "whinter"); -- prepareStatement의 set함수 호출
    	psmt.setString(2, "한겨울");   -- resultSet으로 하는 경우 .get함수 호출가능
    
    	-- 5. SQL문 실행
    	int rows = psmt.executeUpdate(); -- DML(INSERT)하였으니 executeUpdate
    }catce(Exception e){
    	e.printStackTrace();
    }
    -- 6. 닫기
    psmt.close();
    con.close();
    

3. 데이터 저장, 수정, 삭제 (executeUpdate())

1. 데이터 저장 INSERT

```sql
🗣 INSERT INTO 테이블명(열1, 열2, 열3 … 열n)
VALUES (?,?,?…?)
```
  • 작성예시

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class Test {
    	public static void main(String[] args) throws SQLException {
    		Connection con = null;
    
    		try {
    			//JDBC Driver 등록 및 연결
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			con=DriverManager.getConnection("jdbc:mysql://localhost:3306/ksj", "root", "1234");
    
    			//매개변수화된 SQL문 작성
    			String sql = ""+"INSERT INTO users(id,name,pw,age,email)"+
    						"VALUES(?,?,?,?,?)";
    
    			//PreparedStatement 얻기 및 값 지정
    			PreparedStatement psmt = con.prepareStatement(sql);
    			psmt.setString(1, "winter");
    			psmt.setString(2, "한겨울");
    			psmt.setString(3, "12345");
    			psmt.setInt(4, 25);
    			psmt.setString(5, "winter@mycompany.com");
    
    			//SQL문 실행
    			int row = psmt.executeUpdate();
    			System.out.println("저장된 행 수: "+row);
    
    			//PreparedStatement 닫기
    			psmt.close();
    		}
    		catch(Exception e) {
    			e.printStackTrace();
    		}
    		con.close();
    	}
    }
    
  • MySQL users 테이블 확인

  • 작성예시2

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class Test4 {
    
    	public static void main(String[] args) throws SQLException {
    
    		String url = "jdbc:mysql://localhost:3306/ksj";
    		String que = "INSERT INTO emp(empno, ename, job)"
    					+"values(?,?,?)";
    
    		// ?: 주기적 변경해서 입력할 값(바인드 변수)
    		Connection con = null; //인터페이스라 null로 넣을 수 있음
    		PreparedStatement pstmt = null;
    
    		try {
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			con = DriverManager.getConnection(url, "root", "1234");
    
    			pstmt = con.prepareStatement(que);
    			pstmt.setInt(1, 1234);
    			pstmt.setString(2, "Bob");
    			pstmt.setString(3, "ANALYST");
    
    			pstmt.executeUpdate();
    		}catch(Exception e) {
    			e.printStackTrace();
    		}
    		con.close();
    
    	}
    }
    

2. 데이터 수정 UPDATE

🗣 String sql = new StringBulider()
         .append(UPDATE 테이블명 SET)
         .append(”열1 = ?, )
         .append(”열2 = ?, )
         .append(”열n = ?)
        .toString();
  • 작성예시

    package test;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class Test {
    	public static void main(String[] args) throws SQLException {
    		Connection con = null;
    
    		try {
    			//JDBC Driver 등록 및 연결
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			con=DriverManager.getConnection("jdbc:mysql://localhost:3306/ksj", "root", "1234");
    
    			//매개변수화된 SQL문 작성
    			String sql = new StringBuilder()
    					.append("UPDATE users SET ") //users 테이블 셋팅. SET뒤에 띄어쓰기 필수!
    					.append("name=?, ")
    					.append("pw=?, ")
    					.append("age=?, ")
    					.append("email=?")
    					.append("WHERE id=?") //변경 조건은?
    					.toString();
    
    			//PreparedStatement 얻기 및 값 지정
    			PreparedStatement psmt = con.prepareStatement(sql);
    			psmt.setString(1, "테스트"); //번호는 열번호가 아니라 이클립스에 작성한 순서대로
    			psmt.setString(2, "00");
    			psmt.setInt(3, 30);
    			psmt.setString(4, "test@test.com");
    			psmt.setString(5, "snowman"); //1열의 id가 test인 경우 변경
    
    			//SQL문 실행
    			int rows = psmt.executeUpdate(); //오류남. 왜지???
    			System.out.println("저장된 행 수: "+rows);
    
    			//PreparedStatement 닫기
    			psmt.close();
    		}
    		catch(Exception e) {
    			e.printStackTrace();
    		}
    		con.close();
    	}
    }
    
    

3. 데이터 삭제 DELETE

🗣 String sql = DELETE FROM 테이블명 WHERE 열명=?;
  • 작성예시

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    public class Test {
    	public static void main(String[] args) throws SQLException {
    		Connection con = null;
    
    		try {
    			//JDBC Driver 등록 및 연결
    			Class.forName("com.mysql.cj.jdbc.Driver");
    			con=DriverManager.getConnection("jdbc:mysql://localhost:3306/ksj", "root", "1234");
    
    			//매개변수화된 SQL문 작성
    			String sql = "DELETE FROM users WHERE id=?";
    
    			//PreparedStatement 얻기 및 값 지정
    			PreparedStatement psmt = con.prepareStatement(sql);
    			psmt.setString(1, "snowman");
    
    			//SQL문 실행
    			int rows = psmt.executeUpdate();
    			System.out.println("저장된 행 수: "+rows);
    
    			//PreparedStatement 닫기
    			psmt.close();
    		}
    		catch(Exception e) {
    			e.printStackTrace();
    		}
    		con.close();
    	}
    }
    

4. 데이터 읽기 (executeQuery())

  • 데이터를 가져오는 select문일 경우 executeQuery() 메소드 호출
  • executeQuery() 메소드는 가져온 데이터를 ResultSet에 저장하고 리턴

    🗣 ResultSet rs = psmt.executeQuery();
    
  • ResultSet: SELECT문에 기술된 컬럼으로 구성된 행의 집합
  • next(): 첫 번째 데이터 행인 first행을 읽으면서 커서 이동 (boolean형을 반환)
    • n개 데이터 행일 경우: while(rs.next())
    • 1개 데이터 행일 경우: if(rs.next())
      🗣 boolean result = rs.next();
      

데이터 조회 및 가져오기

  • 작성 코드

    package test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class Test {
    	public static void main(String[] args) throws SQLException {
    		Connection con = null;  //DB와 연결하는 인터페이스
    		PreparedStatement psmt = null; //sql문 객체
    		ResultSet rs = null; //sql에 대한 반환(쿼리 실행에 대한 결과값 저장)
    
    		try {
    			String que = "select *from emp";
    
    			con = Mysql.get(); //DB연결: 연결된 Mysql의 함수 호출
    
    			psmt = con.prepareStatement(que);
    			rs = psmt.executeQuery(); //쿼리실행 결과를 rs에 저장
    			//select → executeQuery()
    			//DML(insert, update, delete) → executeUpdate();
    
    			while(rs.next()) { //ResultSet의 함수 next 가져옴
    				//DB에 있는 값들을 가져옴(행 기준)
    				String empno = rs.getString(1); //int를 String으로 가져와도 됨
    				String ename = rs.getString(2);
    				String job = rs.getString(3);
    				int mgr = rs.getInt(4);
    
    				java.sql.Date hiredate = rs.getDate(5); // sql은 생략 가능
    				int sal = rs.getInt(6);
    				int comm = rs.getInt(7);
    				int deptno = rs.getInt(8); //(열번호)
    
    				System.out.println(empno+" "+ename+" "+job);
    			}
    		}catch(Exception e) {
    			e.printStackTrace();
    		}
    		rs.close();
    		psmt.close();
    		con.close();
    	}
    }
    ----------------출력결과------------------------------------
    연동된 MySQL 데이터를 가져옴
    데이터베이스에 연결됨
    1111 gildong student
    2222 gildong student
    7369 SMITH CLERK
    7499 ALLEN SALESMAN
    7521 WARD SALESMAN
    7566 JONES MANAGER
    7654 MARTIN SALESMAN
    7698 BLAKE MANAGER
    7782 CLARK MANAGER
    7788 SCOTT ANALYST
    7839 KING PRESIDENT
    7844 TURNER SALESMAN
    7876 ADAMS CLERK
    7882 히히히 대리
    7900 JAMES CLERK
    7902 FORD ANALYST
    7934 MILLER CLERK
    
  • MySQL에 저장된 emp 테이블

3. 고급 기능

1. 프로시저와 함수호출 (CallableStatement)

  • 프로시저와 함수의 매개변수화 된 호출문을 작성하고 Connection의 prepareCall() 메소드로부터 CallableStatement객체를 얻음

  • 1) 프로시저 호출

    //매개변수화된 호출문 작성과 CallableStatement 얻기
    String sql  = { call 프로시저명(?,?, ) };
    CallableStatment cstmt = con,prepareCall(sql);
    
    // ? 값 지정 및 리턴 타입 지정
    cstmt.setString(1,"summer");
    cstmt.setString(2,"하여름");
    cstmt.setInt(1,25);
    
    //프로시저 실행
    cstmt.execute();
    
  • 2) 함수를 호출

    //매개변수화된 호출문 작성과 CallableStatement 얻기
    String sql =  ? = call 함수명(?,?, ) ;
    CallableStatment cstmt = con,prepareCall(sql);
    
    // ? 값 지정 및 리턴 타입 지정
    cstmt.registerOutParameter(1, Types.*INTEGER*);
    cstmt.setString(2,"winter");
    cstmt.setString(3,"12345");
    
    //함수실행
    cstmt.execute();
    

2. 트랜잭션 처리

  • 트랙잭션(transaction)은 기능 처리의 최소 단위
  • 최소 단위라는 것은 구성된 소작업들을 분리할 수 없으며, 전체를 하나로 봄(모두 성공 or 모두 실패)
  • DB는 트랙잭션을 처리하기 위해 커밋(commint)과 롤백(rollback)제공

    • 커밋(commit): 내부 작업을 모두 성공 처리 (JDBC에서는 DML이 자동 커밋되서 안적어도 됨)
    • 롤백(rollback): 실행 전으로 돌아간다는 의미에서 모두 실패 처리
    • 두 개 이상의 작업 중 첫 번째 작업이 끝나고 커밋이 되면 안되니 자동 커밋기능을 끔
    con.setAutoCommit(false);
    
    Connection con = null;
    try{
    //트랜잭션 시작---------------------
    	//자동 커밋 기능 끄기
    	con.setAutoCommit(false); //하나의 작업만 처리되지 않도록 끔
    
    	//소작업 처리1
    	PreparedStatement pstmt1 = con.prepareStatement("INSERT INTO account (id, balance) VALUES (?, ?)");
    	pstmt1.setString(1, "user");
    	pstmt1.setInt(2, 1000);
    	pstmt1.executeUpdate();
    
    	//소작업 처리2
    	PreparedStatement pstmt2 = con.prepareStatement("UPDATE account SET balance = balance - 100 WHERE id = ?");
    	pstmt2.setString(1, "user");
    	pstmt2.executeUpdate();
    
    	//커밋 -> 모두 성공 처리
    	con.commit();
    }catch(Exception e){
    	con.rollback();    //롤백 -> 모두 실패 처리
    }
    

3. 커넥션 풀 (Connection Pool)

  • 서버가 미리 일정 개수의 DB 커넥션(Connection)을 생성해놓고 관리
    클라이언트가 요청시 새로운 DB 연결을 생성하지않고, 풀(pool)에 있는 커넥션을 빌려주고 작업이 끝나면 다시 반환해서 재사용
  • 많은 요청을 처리할 때 DB 연결/해제의 비용을 줄이고 성능을 향상시킬 수 있다

  • 장점

    • 자원 관리 효율화 : 생성된 Connection을 재사용할 수 있음
    • 성능 향상 : DB연결 시간을 줄일 수 있음
    • 중앙 집중식 관리 : 커넥션 풀을 통해 모든 Connection 수를 관리할 수 있음
    • 동시 처리 성능 향상 : 여러 클라이언트가 동시에 DB에 접근할 때, 빠르게 커넥션을 할당하고 회수
  • 단점

    • 초기 설정 비용 o : 미리 커넥션을 생성해야해서 비용이 들지만 한번 설정하면 이후에는 영향이 거의 없다
    • 자원 낭비 가능성 : 커넥션 풀의 사이즈를 너무 크게 설정 할 경우
    • 커넥션 누수 문제 : 풀에서 커넥션을 제대로 회수하지 않을 경우
    • 병목 현상 발생 : 커넥션 풀의 크기를 너무 작게 설정한 경우
    • 복잡한 설정 : 니프최대 연결 수, 최소 연결 수, 대기 시간 등 여러 파라미터를 잘 맞춰야한다

태그:

카테고리:

업데이트:

댓글남기기