-
6. 자바와 SQL의 힘을 합쳐 필드 생성, 레코드 한 개 조회하기PROGRAMMING/SQL 2022. 4. 24. 02:32
하루입니다.
오늘은 전자상점에 서비스를 제공하려 합니다. 전자제품과 관련된 값으로는 고유한 번호, 이름, 제조사, 가격, 할인판매가, 재고, 판매여부, 제조일이 있습니다.
제가 원하는 건 상점에서 특정 번호를 누르면 제품 추가 / 상세 정보 확인 / 전체 조회 / 변경 / 삭제의 기능을 수행할 수 있는 거예요. 자바와 데이터베이스를 연결해서 자바에 값이 출력되기만 하는 게 아닌 실제로 DB에 값이 들어가게 하려 합니다.

표현계층에서는 고객이 맞는 번호를 누른다면 원하는 작업을 할 수 있게 하고, 영속화 계층에서는 DB와 상호작용하도록 작업하고, 서비스계층에서는 고객이 프로그램을 실행할 때의 업무로직을 짤 거예요. 먼저 VO(value object)를 작성하도록 합시다. 이제부터 vo를 만들 때 주의할 점은 테이블과 닮게 만들어야 한다는 점입니다.

NO, RPRICE, DISCOUNTPRICE, STOCK은 NUMBER / NAME, COMPANY, STATUS는 VARCHAR / CREATEDDATE는 DATE 형식이네요. 필드에 입력할 때는 int, String, Date로 입력하겠습니다.
public class Product private int no; private String name; private String company; private int price; private int discountPrice; private int stock; private String status; private Date createdDate; 기본생성자 생성 getter setter 메소드 생성 toString 재정의다음으론 repo와 app을 생성하고 메뉴의 틀을 잡도록 합시다.
public class ProductInsertApp while (true) { try { System.out.println("------------------------------------"); System.out.println("1.등록 2.전체조회 3.상세정보 4.수정 5.삭제"); System.out.println("------------------------------------"); System.out.println("메뉴를 선택해주세요."); int menuNo = reader.readInt(); System.out.println(); if (menuNo == 1) { System.out.println("<< 새 상품 등록 >>"); System.out.println("상품등록 정보를 입력하세요."); System.out.println("상품이름 입력"); String name = reader.readString(); System.out.println("제조회사 입력"); String company = reader.readString(); System.out.println("상품가격 입력"); int price = reader.readInt(); System.out.println("입고수량 입력"); int stock = reader.readInt(); System.out.println("[처리완료] 신규 상품이 등록되었습니다."); } } catch (Exception e) { e.printStackTrace(); System.out.println("에러가 발생했습니다."); } }이 다음엔 뭐가 필요할까요? 신규 상품을 등록할 수 있는 업무로직이 필요하겠죠. ProductRepository에서 업무로직을 만들겠습니다.
public class ProductRepository public void insertProduct(Product product) throws ClassNotFoundException, SQLException { String sql = "insert into sample_products " + "(product_no, product_name, product_company, product_price, product_stock) " + "values " + "(product_seq.nextval, ?, ?, ?, ?)"; Class.forName("oracle.jdbc.OracleDriver"); Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "xx", "xxxxxxxx"); PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, product.getName()); pstmt.setString(2, product.getCompany()); pstmt.setInt(3, product.getPrice()); pstmt.setInt(4, product.getStock()); pstmt.executeUpdate(); pstmt.close(); connection.close(); }헉 그런데요. 컬럼은 많은데 왜 저 네 가지만 데이터를 입력하게 하나요?
그 이유는 1. not null인 값만 입력할 건데 그럼 no name company price stock 총 다섯 개임.
2. 그 중에서도 no는 시퀀스를 통해 숫자가 자동으로 1씩 올라가도록 설정해 둠.
3. 자동설정 / null 허용을 제외하면 name company price stock 총 네 개.
4. (product_seq.nextval, ?, ?, ?, ?) 이 부분에서 no에 시퀀스를 대입한 것을 알 수 있다.
헉 그렇군요!
다음은 제품 상세정보 확인과 전체 상품 조회를 구현하려 합니다. 의외로 ... 이 부분이 꽤나 중요합니다. 더 정확하게 말하자면 데이터 조회하기에서 [조회결과가 없거나 한 행만 조회되는 경우] 와 [조회결과가 없거나 여러 행이 조회되는 경우]로 나눌 수 있겠네요! 그리고 ResultSet이라는 것의 작동 원리도 알아야 합니다!
데이터 조회하기 (SELECT)
1. 조회결과가 없거나 한 행만 조회되는 경우
- PRIMARY KEY로 설정된 컬럼이 조회조건으로 이용되는 경우
- 컬럼에 PK가 있다면 무조건 값이 있어야 하며 같은 값이 없어야 한다.
- 이메일로 조회, 주민번호로 조회, 사원번호로 조회 등 ...
- UNIQUE로 설정된 컬럼이 조회조건으로 이용되는 경우
- 컬럼에 UNIQUE가 있다면 같은 값이 없어야하나 null은 있을 수도 있습니다.
- 새로운 사원이 와서 사원번호를 발행해 줘야 하는 상황 (사원번호 없지만 중복은 안 됨)
// 상품테이블에서 상품번호(Primary key)로 조회하기 public Product getProduct(int productNo) { ... }] // 사원테이블에서 사원아이디(Primary key)로 조회하기 public Employee getEmployee(int employeeId) { ... } // 직종테이블에서 직종아이디(Primary key)로 조회하기 public Job getJob(int jobId) { ... } // 사원테이블에서 이메일(Unique)로 조회하기 public Employee getEmployeeByEmail(String email) { ... }- 이 값을 출력하기 위해서는?
- RS 객체에 조회결과가 저장되는데, 하나도 없거나 한 개만 존재하므로 반복작업을 수행할 필요가 없다.
- 이게 무슨 뜻이냐! 반복할 필요 없이 존재여부만 확인하면 되는 것.
- if(rs.next)
2.조회결과가 없거나 여러 행이 조회되는 경우
- PRIMARY KEY, UNIQUE로 설정되어 있지 않는 컬럼이 조회조건으로 이용되는 경우
- 이름, 수량, 급여, 입사일, 소속 부서 등 ...
// 상품테이블에서 상품이름으로 조회하기 public List<Product> getProductByName(String name) { ... } // 사원테이블에서 급여로 조회하기 public List<Employee> getEmployeeBySalary(double Salary) { ... } // 사원테이블에서 소속부서 아이디로 조회하기 public List<Employee> getEmployeeByDepartmentId(int departmentId) { ... }- RS 객체에 조회결과가 저장되는데, 하나도 없거나 여러 개가 존재하므로 반복작업을 수행해야 한다.
- 맨 마지막 행까지 반복해서 데이터를 꺼내야 한다.
- 이럴 때 WHILE문이 사용된다!
- while(rs.next) 를 사용한다.
- rs.next()는 커서가 위치한 곳에 데이터행이 존재하면 true를 반환한다.
- 따라서 rs.next()의 실행결과가 true라면 계속 RS에서 데이터를 추출할 수 있다.
- 이 값은 controller에서 다시 향상된-for문을 사용하여 꺼낸다!
* 추가사항
DEPARTMENTS 테이블에서 DEPARTMENT_ID는 PRIMARY_KEY라고 하자. EMPLOYEES 테이블에서 DEPARTMENT_ID는 PRIMARY KEY도 UNIQUE도 아니라고 하자. DEPARTMENTS 테이블에서 DEPARTMENT_ID를 조회하면 0건 아님 1건이, EMPLOYEES에서 DEPARTMENT_ID를 조회하면 0건 아님 여러 건이 나온다. 1건이 나올 수도 있으나 앞으로 여러 건이 될 수 있다.
ResultSet(이 뭔가요)

사실 ... 이 그림 하나로 모두 설명됩니다 ...
PreparedStatement 인터페이스의 메소드에서 SELECT는 ResultSet executeQuery()를 사용하던 거 기억 나시나요? 이 때 ResultSet(이하 RS)에는 SELECT문의 실행결과가 들어가 있습니다. 하단의 RS 객체를 보면 데이터들이 들어 있는 걸 볼 수 있습니다. RS에는 커서가 내장되어 있는데요, 처음부터 행을 가리키는 것이 아닌 데이터의 하나 위에 위치하고 있습니다. 이 커서를 한 행 내리는 메소드는 boolean next()입니다. 만약 내렸는데 값이 있다면 true! 없다면 false! 를 반환합니다. 왠지 if for while이 생각나죠 ^^ ... ?
커서가 있는 행에서 데이터를 가져오기 위해서는 int no = rs.getint(product_no); 와 같은 형태로 적으면 됩니다!
그럼 이제 코딩을 해 볼까요!
상품번호(한 개)를 전달받아서 일치하는 상품정보를 조회해서 반환하겠습니다!
먼저 생각을 ... 해 봅니다 ... 번호를 입력했을 때 정보가 나오게 하는 메소드니까 productNo가 매개변수(대충 이 값이 필요하다는 뜻임)일테고 ... sample_product 테이블에서 전체 데이터를 where product_no에 따라 꺼내야 할 것. select니까 RS를 사용해서 상품 번호가 nnnn인 것을 찾으면 되겠구나 ... 나머지 과정은 위와 같습니다. 코딩! 시작!
- 상품번호 한 개 전달받기 위해 DAO에 코딩한 내용 -
public Product getProductByNo (int productNo) throws ClassNotFoundException, SQLException { Product product = null; String sql = "select product_no, product_name, product_company, product_price, product_discount_price, product_stock, product_status, product_created_date " + "from sample_product " + "where product_no = ? "; Class.forName("오라클 오라클 드라이버 연결"); Connection connection = DriverManager.getConnection("포트 아이디 비밀번호"); PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setInt(1, productNo); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { product = new Product(); // int no = rs.getInt("product_no"); // product.setNo(rs.getInt("product_no")); // 아래와 같은 말이다. 간략화(?)한 것. product.setNo(rs.getInt("product_no")); product.setName(rs.getString("producy_name")); product.setCompany(rs.getString("product_company")); product.setPrice(rs.getInt("product_price")); product.setDiscountPrice(rs.getInt("product_discount_price")); product.setDiscountPrice(rs.getInt("product_discount_price")); product.setStock(rs.getInt("product_stock")); product.setCreatedDate(rs.getDate("createdDate")); } rs.close(); pstmt.close(); connection.close(); return product; }- 코드 설명 : getProductByNo라는 메소드를 repo에 만들었다. 이 메소드는 productNo를 매개변수로 받는다. 왜냐? 우리는 상품번호를 받아서 그걸 찾을 거거든. 이 기능을 구현할 메소드가 No 메소드니까 당연히 상품번호를 받아야 함. 쿼리문을 작성한다. 우리가 얻고자 하는 건 번호라서 번호에 ? 표시를 한다. 띄어쓰기와 오타 검수할 것. DB에 연결한다.
- pstmt.setInt(1, productNo);의 뜻은 저기 ?가 1번째 값(순서)이고 그 자리에 productNo를 넣는다는 뜻이다. 그럼 전달받은 productNo가 sql where문으로 들어가서 같은 번호를 찾겠지. 내가 헷갈렸어서 볼드 표시.
- Rs를 사용한다. 위에서 말했듯 하나하나 내장 커서를 내리며 사용자가 입력한 productNo와 일치하는 product_no가 있나 찾는 것. 없다면 null값을 반환하겠고. 있다면 밑의 get set을 실행할 것. 사실 아직도 get set은 잘 모르겠다. 대강 이해한 걸 적자면 이 코드에서는 db에 있는 값들을 rs.get을 이용해 얻고 그 값들을 set을 사용해서 변수(?) int no 여기 이런 값들에 담는다는 것. 아무튼 잘 찾는다면 db의 값을 자바 println에서도 볼 수 있는 것이다.
- 마무리는 항상 close()로. 입출력 다 있는 메소드니까 return도 잊으면 안 된다.
이제 이걸 출력해야겠죠. 출력은 App에서 해 보겠습니다. 앞서 말했듯 if문을 사용해 내가 찾는 번호가 db에 있다면 상품 정보와 "[처리 완료] 상품정보를 확인하세요." 가 출력되고, 없다면 "[처리 완료] 상품번호와 일치하는 상품정보가 존재하지 않습니다." 라고 뜨게 할 것입니다.
} else if (menuNo == 3) { System.out.println("<< 상품 상세정보 조회 >>"); System.out.println("상품번호로 상품상세정보를 조회해 보세요."); System.out.println("상품번호 입력"); int productNo = reader.readInt(); Product product = productRepository.getProductByNo(productNo); if (product == null) { System.out.println("[처리 완료] 상품번호와 일치하는 상품정보가 존재하지 않습니다."); } else { System.out.println("------------------------------------"); System.out.println("상품번호: " + product.getNo()); 상품번호, 상품이름, 제조회사, 정상가격, 할인가격, 판매상태, 재고수, 등록일자 동일 System.out.println("------------------------------------"); System.out.println(""); } System.out.println("[처리 완료] 상품정보를 확인하세요."); }
급 마무리
감사합니다. 안녕히 계세요.
'PROGRAMMING > SQL' 카테고리의 다른 글
[ SQL ] 오라클 내장함수 1. 단일행함수의 문자함수 (0) 2022.04.25 [ SQL ] DML 요약 및 연습. 작성 시 주의 사항. (0) 2022.04.25 5. JDBC가 뭐고 어떻게 사용하나요? (0) 2022.04.22 4. DML이 뭐고 어떻게 사용하나요? [ INSERT, UPDATE, DELETE ] (0) 2022.04.21 3. DML이 뭐고 어떻게 사용하나요? [ SELECT문(FROM, WHERE, IN, ORDER BY, DISTINCT) ] (0) 2022.04.21