[JAVA] JDBC2 (Java Database Connectivity)

JDBC, SQL, JDBC Utility, DAO(Data Access Object), VO(Value Object), DTO(Data Transfer Object)

Posted by iheese on April 27, 2022 · 23 mins read

JDBC 연결, SQL 처리, DB 연결 해제까지

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTest {

	public static void main(String[] args) {
		
		Connection conn = null;
		PreparedStatement stmt = null;
		
		try {
        	//1. 드라이버 객체 생성(로드)
			DriverManager.registerDriver(new org.h2.Driver());
			
            //2. DB 연결(Connection 객체 생성)
            String jdbcUrl = "jdbc:h2:tcp://localhost/~/test";
			conn = DriverManager.getConnection(jdbcUrl, "sa", "");
			//3. SQL  전송 준비
			String sql = "insert into animal values(?, ?, ?, ?)";
			stmt = conn.prepareStatement(sql);
			
            //4. SQL 전송
			stmt.setString(1, "NUM1");
			stmt.setString(2, "Tory");
			stmt.setInt(3, 5);
			stmt.setString(4, "Dog");
			
			stmt.executeUpdate();
            
		} catch (SQLException e) {
			e.printStackTrace();
            
            //5. DB 연결 종료
		} finally {
			try {
				stmt.close();
			}catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}
  • JDBC를 사용하는 과정은 길고 복잡하여 객체를 통해 쉽게 만들 수 있다.


JDBC Utility

  • JDBC Utility는 JDBC 과정의 공통된 부분을 클래스로 만들어 과정을 쉽고 단순하게 만들 수 있다.
  • SQL 관련 부분(3, 4단계)은 매번 달라질 수 있으니 나머지 과정을 클래스로 만들면 된다.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCUtility{
	public static Connection getConnection() {
		Connection conn = null;
		try {
        	//1. 드라이버 객체 생성(로드)
			DriverManager.registerDriver(new org.h2.Driver());
			
            //2. DB 연결(Connection 객체 생성)
            String jdbcUrl = "jdbc:h2:tcp://localhost/~/test";
			conn = DriverManager.getConnection(jdbcUrl, "sa", "");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
    
	//5. DB 연결 종료
	public static void close(PreparedStatement stmt, Connection conn) {
		try {
			stmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

}


  • JDBCUtility를 이용해서 첫번째 코드를 재작성해보자
public class JDBCTest {

	public static void main(String[] args) {
		
		Connection conn = null;
		PreparedStatement stmt = null;
		
		try {
			// 1,2단계
            conn=JDBCUtility.getConnection();
			
			String sql = "insert into animal values(?, ?, ?, ?)";
			stmt = conn.prepareStatement(sql);

			stmt.setString(1, "NUM1");
			stmt.setString(2, "Tory");
			stmt.setInt(3, 5);
			stmt.setString(4, "Dog");
			
			stmt.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			
        //5단계 
		JDBCUtility.close(stmt, conn);
		}
	}
}
  • 드라이버를 로드하고 DB에 연결하여 Connection을 리턴하는 부분과 DB 연결 종료 부분을 JDBCUtility 메소드로 대체했다.

  • SELECT문을 사용하고 연결을 해제할 때는 ResultSet도 닫아줘야 하므로 JDBCUtility의 close 메소드에 rs.close() 를 추가해줘야 한다.

(...)
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
		try {
			rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			stmt.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}


DAO(Data Access Object) 패턴

  • JDBCUtility는 DB 연결과 해제만 구현했기 때문에 SQL 관련 부분을 제외하고 이용할 수 있다.
  • DAO는 DB의 각 테이블 별로 클래스 내 SQL 부분(SELECT, INSERT, UPDATE, DELETE 메소드)을 구현하여 JDBC 과정을 더 쉽게 이용할 수 있다.


  • DAO의 SELECT 부분 실습
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AnimalDAO {
	private Connection conn = null;
	private PreparedStatement stmt = null;
	private ResultSet rs = null;
	
	private String ANIMAL_LIST = "select * from animal"; //SQL문
	
	public void getAnimalList() {
		try {
			conn = JDBCUtility.getConnection();
			stmt = conn.prepareStatement(ANIMAL_LIST);
			rs = stmt.executeQuery();
            
			while(rs.next()) {
				System.out.print(rs.getString("ANIMAL_NO") + ", ");
				System.out.print(rs.getString("NAME") + ", ");
				System.out.print(rs.getInt("AGE") + ", ");
				System.out.println(rs.getString("SPECIES"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtility.close(rs, stmt, conn);
		}
	}
}

  • DB 연결, 해제 부분은 JDBCUtility를 이용했다.


  • DAO의 INSERT 부분 실습
(...)

private String ANIMAL_INSERT = "insert into animal values(?, ?, ?, ?)"; //SQL문

public void insertAnimal(String animalNo, String name, int age, String species) {
	try {
		conn = JDBCUtility.getConnection();
		stmt = conn.prepareStatement(ANIMAL_INSERT);
        
		stmt.setString(1, animalNo);
		stmt.setString(2, name);
		stmt.setInt(3, age);
		stmt.setString(4, species);
        
		stmt.executeUpdate();
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		JDBCUtility.close(stmt, conn);
	}
}

(...)


  • DAO의 UPDATE 부분 실습
(...)

private String ANIMAL_UPDATE = "update animal set name = ?, age = ? where animal_no = ?"; //SQL문

public void updateAnimal(String name, int age, String animalNo) {
	try {
		conn = JDBCUtility.getConnection();
		stmt = conn.prepareStatement(ANIMAL_UPDATE);
        
        stmt.setString(1, name);
        stmt.setInt(2, age);
		stmt.setString(3, animalNo);

		stmt.executeUpdate();
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		JDBCUtility.close(stmt, conn);
	}
}

(...)


  • DAO의 DELETE 부분 실습
(...)

private String ANIMAL_DELETE = "delete animal where animal_no = ?"; //SQL문

public void deleteAnimal(String animalNo) {
	try {
		conn = JDBCUtility.getConnection();
		stmt = conn.prepareStatement(ANIMAL_DELETE);
        
		stmt.setString(1, animalNo);
		stmt.executeUpdate();
        
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		JDBCUtility.close(stmt, conn);
	}
}


  • DAO 객체, 메소드 실습
public class DaoTest {
	public static void main(String[] args) {
    
		AnimalDAO dao = new AnimalDAO(); //DAO 객체 생성
		
        dao.getAnimalList(); // 데이터 조회
        dao.insertAnimal("NUM5" , "Nabong", 3, "Cat"); // 데이터 입력
        dao.updateAnimal("Nabi", 4, "NUM5"); //데이터 수정
        dao.deleteAnimaml("NUM5") // 데이터 삭제
	}
}


VO(Value Object) 패턴

  • 입력 값을 그 자체를 표현하는 객체이며, read-only 의 성격을 가진다.
  • getter 외의 로직을 포함할 수 있으며, 불변성(객체의 정보가 변경되지 않음)을 보장한다.
  • 서로 다른 이름의 객체라도 모든 속성 값이 같다면 두 인스턴스는 같은 객체라 할 수 있다.
    • equals(), hashcode()을 오버라이딩을 해야한다.
  • setter 메소드를 가지면 안되고, 생성자를 통해서만 값을 초기화 해야 한다.
  • DTO와 비슷한 부분이 있지만 차이가 있다.

DTO(Data Transfer Object)

  • 계층 간의 데이터 교환을 위해 사용되는 객체이다. (오직 이 목적만 가진다.)
  • 로직을 가지지 않고, getter,setter 메소드만 가진다.
    • 안정성을 위해 의도적으로 setter를 없애고 생성자로 값을 넣고 불변하게 사용하기도 한다.


VO, DAO 이용한 실습

  • AnimalVO 를 만들어 입력 값 그 자체를 표현하는 객체를 만들어준다.
  • 생성자로만 값을 받고 getter만 구현하여 불변성을 보장하는 객체를 만들었다.
public class AnimalVO {
	private String animalNo;
	private String name;
	private int age;
	private String species;
	
		
	// SELECT, INSERT용 생성자
	public AnimalVO(String animalNo,String name,int age,String species){
		this.animalNo=animalNo;
		this.name=name;
		this.age=age;
		this.species=species;
	}
	//UPDATE용 생성자
	public AnimalVO(String name,int age, String animalNo){
		this.animalNo=animalNo;
		this.name=name;
		this.age=age;
	}
	//DELETE용 생성자
	public AnimalVO(String animalNo){
		this.animalNo=animalNo;
	}
	
	public String getAnimalNo() {
		return animalNo;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public String getSpecies() {
		return species;
	}
}


  • VO 패턴 적용을 위한 DAO의 SELECT 부분 변경
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


public class AnimalDAO {
	private Connection conn = null;
	private PreparedStatement stmt = null;
	private ResultSet rs = null;
	
	private String ANIMAL_LIST = "select * from animal";
	
	public List<AnimalVO> getAnimalList() {
		List<AnimalVO> animalList = new ArrayList<AnimalVO>();
       
      	try {
			conn = JDBCUtility.getConnection();
			stmt = conn.prepareStatement(ANIMAL_LIST);
			rs = stmt.executeQuery();

			while(rs.next()) {
				String animalNo=rs.getString("ANIMAL_NO");
				String animalName=rs.getString("NAME");
				int animalAge = rs.getInt("AGE");
				String animalSpecies=rs.getString("SPECIES");
				AnimalVO animal = new AnimalVO(animalNo, animalName, animalAge, animalSpecies);
            	animalList.add(animal);
			}
		}catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtility.close(rs, stmt, conn);
		}
        return animalList;
	}

  • SQL로 받아온 한 행을 하나의 객체로 생성했다.
  • 그 객체를 리스트에 넣은 뒤 리턴해주었다.


  • VO 패턴 적용을 위한 DAO의 INSERT 부분 변경
(...)

	private String ANIMAL_INSERT = "insert into animal values(?, ?, ?, ?)"; 
    
	public void insertAnimal(AnimalVO vo) {
		try {
			conn = JDBCUtility.getConnection();
			stmt = conn.prepareStatement(ANIMAL_INSERT);
	        
			stmt.setString(1, vo.getAnimalNo());
			stmt.setString(2, vo.getName());
			stmt.setInt(3, vo.getAge());
			stmt.setString(4, vo.getSpecies());
	        
			stmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtility.close(stmt, conn);
		}
	}
    
(...)


  • VO 패턴 적용을 위한 DAO의 UPDATE 부분 변경
(...)

	private String ANIMAL_UPDATE = "update animal set name = ?, age = ? where animal_no = ?";

	public void updateAnimal(AnimalVO vo) {
		try {
			conn = JDBCUtility.getConnection();
			stmt = conn.prepareStatement(ANIMAL_UPDATE);
	        
	        stmt.setString(1, vo.getName());
	        stmt.setInt(2,vo.getAge());
			stmt.setString(3, vo.getAnimalNo());

			stmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtility.close(stmt, conn);
		}
	}
    
(...)    


  • VO 패턴 적용을 위한 DAO의 DELETE 부분 변경
(...)

	private String ANIMAL_DELETE = "delete animal where animal_no = ?";

	public void deleteAnimal(AnimalVO vo) {
		try {
			conn = JDBCUtility.getConnection();
			stmt = conn.prepareStatement(ANIMAL_DELETE);

            stmt.setString(1, vo.getAnimalNo());
            stmt.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtility.close(stmt, conn);
        }
    }
}
  • INSERT, UPDATE, DELETE 모두 메소드에 VO 객체를 넣어주었다.
  • 각 메소드에 맞는 생성자를 이용해 객체를 생성하고 입력해주면 getter 메소드를 통해 ? 파라미터에 입력값이 입력된다.


  • VO 패턴이 적용된 DAO 실습
import java.util.List;

public class AniTest {

	public static void main(String[] args) {
		AnimalDAO dao = new AnimalDAO();
		
		//SELECT
		List<AnimalVO> animalList =dao.getAnimalList();
		
		for(AnimalVO animal : animalList) {
			System.out.print(animal.getAnimalNo()+", ");
			System.out.print(animal.getName()+", ");
			System.out.print(animal.getAge()+", ");
			System.out.println(animal.getSpecies());
		}
		
		//INSERT
		AnimalVO vo1 = new AnimalVO("NUM5","Bongi",2,"Cat");
		dao.insertAnimal(vo1);
		
		//UPDATE
		AnimalVO vo2 = new AnimalVO("Bongsuni",3,"NUM5");
		dao.updateAnimal(vo2);
		
		//DELETE
		AnimalVO vo3 = new AnimalVO("NUM5");
		dao.deleteAnimal(vo3);
	}
}


Reference: