JDBC Programming

이리·2024년 7월 26일
0
post-custom-banner

Java를 사용할 경우 데이터베이스와 연동을 위해서는 반드시 JDBC 프로그래밍을 진행해야한다.
그 중 JDBC에서 제공하는 인터페이스와 간단한 연결 코드에 대해서 정리해보았다...



**임의로 database, table 등등 명을 변경.

DAO (Data Access Object) Interface

  • DB의 Data에 접근하기 위한 객체 → DB 접근 코드와 APP 로직 코드의 분리

    UserDAO - DB와 상호작용하는 메서드 집합 의미
    UserDAOImpl - DB와 실제 상호작용하는 메서드 집합 의미
    ⇒ 나중에 구현 클래스를 변경해도 인터페이스 사용하는 다른 객체에 영향 X
    ⇒ 다른 DB 를 사용할 경우 다른 Driver에 연결해야하는데 이경우 서로 영향을 끼치지 않음

  • 자신이 필요한 Interface를 DAO 에 던지고, DAO는 Interface를 구현한 객체를 사용자에게 돌려줌
    • ⇒ 이게 무슨말인가?

    • DAO 패턴에서는 데이터베이스 작업을 정의하는 인터페이스를 만든다 = CRUD와 같은 기본적인 데이터베이스 작업들이 정의됨

    • EX 코드

      public interface UserDAO{
      	void addUser(User user);
      	User getUserById(int id);
      	List<User> getAllUser();
      	void updateUser(User user);
          void deleteUser(int id);
      }

DAOImpl - Implementation 구현 클래스

  • 실제 데이터베이스와 상호작용하는 코드가 삽입 = 구체적인 접근 방식을 정의
  • private Connection conn = null ⇒ Connection 타입 인스턴스 변수 : Java SQL패키지에서 DB 연결을 의미 ⇒ Statement, PreparedStatement, CallableStatement 객체 생성을 위한 메서드 제공
    • Statement - conn.createStatement()
    • PreparedStatement - conn.prepareStatement()
    • CallableStatement - conn.prepareCall
  • UserDAOImpl
    public class UserDAOImpl implementation UserDAO{
    
      // 어떤 DB가 연결될지 모르기 때문에 null 초기화 
    	private Connection conn = null;
    	
    	// 연결에 사용할 자원 
    	private static String driver = "com.mysql.jdbc.Driver";
      private static String url = "jdbc:mysql://localhost:3306/길동";
      private static String user = "홍길동";
      private static String password = "1234";
    	
    	// 생성자(생성과 동시에 연결 시도)
    	// 외부와 연결하는 작업이기때문에 try 구문 사용  
    	public UserDAOImpl() {
          try{
              Class.forName(driver); // 드라이버 로드, 실행
              conn = DriverManager.getConnection(url, user, password);
    
              System.out.println("DB 연결");
    
          }catch (ClassNotFoundException e) {
              e.printStackTrace();
          }catch(SQLException e) {
              e.printStackTrace();
          }
        }
    • Class.forName(”로드할 클래스”) : 동적으로 클래스를 로드하는 방식 (런타임동적로드 방식을 지원)
    • DriverManager.getConnection(url, user, password) : Connection 객체를 return
    • Client와 DB의 연결된 세션 역할
         

DAOImpl 세부 메서드 구현

Statement

  • Statement stmt = conn.createStatement()
    • createStatement() : Statement 객체를 생성하기위한 메서드, Statement 객체를 반환
    • SQLException 해결 필요
  • Statement 객체
    • JDBC API에서 SQL 쿼리를 실행하기위해 사용되는 객체
  • Statement 실행 메서드
    • ResultSet executeQuery(SQL) : select 문
    • int executeUpdate(SQL) : insert, update, delete 문

ResultSet

  • ResultSet rs = stmt.executeQuery();
    • rs.next() ⇒ 커서가 이동하면서 데이터 읽어들임
  • 컬럼 값 추출 방법
    • getXXX(”가져올컬럼명”)
    • ex. getString(””), getInt(””), getLong(””), getDouble(””)

PreparedStatement

  • SQL문에 값을 넣을때 파라미터화 해서 처리
  • PreparedStatement pstmt = conn.prepareStatement(sql);
  • 파라미터 설정
    • pstmt.setXXX(파라미터순서, 값-보통 Getter메서드 호출)
    • setString(), setInt(), setLong(), setDouble()

Create 메서드

@Override
    public int create(FriendVO friend) throws SQLException {
        String sql = "INSERT INTO 길동 VALUES ( ?, ?, ?, ?)";
        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setInt(1, friend.getSsn());
        stmt.setString(2, friend.getName());
        stmt.setString(3, friend.getDept_no());
        stmt.setString(4, friend.getBirth_date());

        return stmt.executeUpdate();
    }

⇒ stmt.setXXX(파라미터 순서, 게터 메서드)

⇒ return stmt.executeUpdate() ⇒ 적용된 행의 수가 return = 1

Delete 메서드

@Override
    public int delete(Integer ssn) throws SQLException {
        String sql = "DELETE FROM 길동 WHERE ssn = ?";
        try(Connection conn = DriverManager.getConnection(url, user, password);
		        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setInt(1, ssn);

            return stmt.executeUpdate();
        }
    }

⇒ 지울 ssn을 명시해줘야하므로 stmt.setInt(1, ssn)

Update 메서드

@Override
    public int update(FriendVO friend) throws SQLException {
        String sql = "UPDATE 길동 SET name = ?, dept_no = ?, birth_date = ? WHERE ssn = ?";
        try(Connection conn = DriverManager.getConnection(url, user, password);
		        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, friend.getName());
            stmt.setString(2, friend.getDept_no());
            stmt.setString(3, friend.getBirth_date());
            stmt.setInt(4, friend.getSsn());
            return stmt.executeUpdate();
        }
    }

⇒ 수정된 fiend를 해당하는 ssn에 교체

⇒ return stmt.executeUpdate()

Get 메서드

  • 완성본을 불러오기 위해서는 받아온 ResultSet을 FriendVO 객체로 변환이 필요
  • map(ResultSet rs) ⇒ 매핑 필요
    private FriendVO map(ResultSet rs) throws SQLException {
            FriendVO friend = new FriendVO();
            friend.setSsn(rs.getInt("ssn"));
            friend.setName(rs.getString("name"));
            friend.setDept_no(rs.getString("dept_no"));
            friend.setBirth_date(rs.getString("birth_date"));
            return friend;
        }
    ⇒ friend.setSsn(rs.getInt(”ssn”)); ⇒ rs.get@컬럼타입@(”가져올 컬럼명”)
  • get 메서드 구현
    @Override
        public List<FriendVO> getAll() throws SQLException {
            List<FriendVO> friends = new ArrayList<>();
            String sql = "SELECT * FROM 길동";
    
            try(Connection conn = DriverManager.getConnection(url, user, password);
    		        PreparedStatement stmt = conn.prepareStatement(sql)){
                ResultSet rs = stmt.executeQuery();
                while(rs.next()){
                    FriendVO friend = map(rs);
                    friends.add(friend);
                }
            }
            return friends;
        }
    ⇒ return 전체 리스트
  • 특정 ssn만 가져오는 구문
    • Optional 객체

      • NullPointerException 방지
      • 명시적 처리 요구 : 메서드의 반환값이 없을수 있음을 표시
    • Optional 주요 메서드
      - isPresent(): 값이 존재하는지 확인
      - orElse(T other): 값이 존재하면 그 값을 반환하고, 값이 없으면 대체값 반환
      - orElseGet
      - orElseThrow(): 값이 존재하면 그 값을 반환하고, 값이 없으면 예외를 던짐

      @Override
          public Optional<FriendVO> get(Integer ssn) throws SQLException {
              String sql = "SELECT * FROM 길동 WHERE ssn = ?";
              try(Connection conn = DriverManager.getConnection(url, user, password);
      		        PreparedStatement stmt = conn.prepareStatement(sql)){
                  stmt.setInt(1, ssn);
                  try(ResultSet rs = stmt.executeQuery()){
                      if(rs.next()){
                          return Optional.of(map(rs));
                      }
                  }
              }
              return Optional.empty();
          }

      ⇒ Optional.of(map(rs)) : 값을 담고있는 Optional 객체를 생성

      → 주어진 값이 null이 아님을 보장 (null일 경우 NullPointerException 발생)

      → Optional 객체 생성

      ⇒ Optional.empty(): 값이 없는 빈 Optional 객체를 반환

완성 Code

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class FriendDAOImpl implements FriendDAO {

    private String driver = "com.mysql.cj.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/길동";
    private String user = "홍길동";
    private String password = "1234";

    public FriendDAOImpl() {
        try{
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public int create(FriendVO friend) throws SQLException {
        String sql = "INSERT INTO 길동 VALUES (?, ?, ?, ?)";
        try(Connection conn = DriverManager.getConnection(url, user, password);
        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, friend.getSsn());
            stmt.setString(2, friend.getName());
            stmt.setString(3, friend.getDept_no());
            stmt.setString(4, friend.getBirth_date());
            return stmt.executeUpdate();
        }
    }

    @Override
    public int update(FriendVO friend) throws SQLException {
        String sql = "UPDATE 길동 SET name = ?, dept_no = ?, birth_date = ? WHERE ssn = ?";
        try(Connection conn = DriverManager.getConnection(url, user, password);
        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, friend.getName());
            stmt.setString(2, friend.getDept_no());
            stmt.setString(3, friend.getBirth_date());
            stmt.setString(4, friend.getSsn());
            return stmt.executeUpdate();
        }
    }

    @Override
    public int delete(String ssn) throws SQLException {
        String sql = "DELETE FROM 길동 WHERE ssn = ?";
        try(Connection conn = DriverManager.getConnection(url, user, password);
        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, ssn);
            return stmt.executeUpdate();
        }
    }

    public FriendVO map(ResultSet rs) throws SQLException {
        FriendVO friend = new FriendVO();
        friend.setSsn(rs.getString("ssn"));
        friend.setName(rs.getString("name"));
        friend.setDept_no(rs.getString("dept_no"));
        friend.setBirth_date(rs.getString("birth_date"));
        return friend;
    }

    @Override
    public List<FriendVO> getAll() throws SQLException {
        List<FriendVO> friends = new ArrayList<>();
        String sql = "SELECT * FROM 길동";
        try(Connection conn = DriverManager.getConnection(url, user, password);
        PreparedStatement stmt = conn.prepareStatement(sql);){
            try(ResultSet rs = stmt.executeQuery();){
                while (rs.next()) {
                    friends.add(map(rs));
                }
            }
            return friends;
        }
    }

    @Override
    public Optional<FriendVO> getBySsn(String ssn) throws SQLException {
        String sql = "SELECT * FROM 길동 WHERE ssn = ?";
        try(Connection conn = DriverManager.getConnection(url, user, password);
        PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, ssn);
            try(ResultSet rs = stmt.executeQuery();){
                if(rs.next()){
                    return Optional.of(map(rs));
                }
            }
        }
        return Optional.empty();
    }
}
post-custom-banner

0개의 댓글