수업내용/SQL

[2022.10.26.수] ibatis, 자바로 데이터베이스 액세스

주니어주니 2022. 10. 26. 18:29

 

 

2. 자바로 데이터베이스 액세스

 

 

2-1. 구현 내용

 

1. 프로젝트 , 패키지 만들기 (controller, dao, service, vo)

 

2. vo 객체 만들기

  : 오라클의 sample_users, sample_products 객체를 이클립스의 vo객체로 만들기

 

3. Service 클래스 내용 구현

  • 업무로직이 구현되는 클래스
  • 메소드 - 요구사항(기능) 하나와 대응
    * 대체로 요구사항 하나마다 업무로직 메소드 하나가 필요
    * 업무로직을 구현하기 위해서는 대체로 1번 이상의 데이터베이스 액세스 작업 필요 
    * 업무로직을 구현하기 위해서 DAO 객체의 메소드를 1번 이상 호출하게 된다. 

4. DAO 클래스 구현

  • 데이터베이스 액세스 작업이 구현되는 클래스
  • 메소드 - SQL 하나와 대응 
    * SQL문 하나마다 메소드 하나가 필요
  • CRUD 작업을 구현
    - Create : INSERT문   ( 출력값 - 무조건 void )
    - Read : SELECT문    ( 출력값 - 기본자료형,
                                                         객체 1개        (primary key, unique로 조회할 경우),
                                                         List<객체>    (나머지로 조회할 경우) ) 
    - Update : UPDATE문 ( 출력값 - 무조건 void ) 
    - Delete : DELETE문   ( 출력값 - 무조건 void ) 

 

 

* DAO 클래스에서 SQL당 작성해야 하는 메소드

-- public User getUserById(String id) { ... }
select * from sample_users where user_id = 'hong1';

-- public User getUserByEmail(String email) { ... }
select * from sample_users where user_email = 'hong1@gmail.com';

-- public List<Employee> getEmployeesByDepartmentId(int departmentId) { ... }
select *
from employees
where department_id = 90;

-- public List<Employee> getEmployeesByJobId(String jobId) { ... }
select * 
from employees
where job_id = 'IT_PROG';

-- public Employee getEmployeeById(int employeeId) { ... }
select *
from employees
where employee_id = 100;

-- public List<Department> getDepartmentsByLocationId(int locationId) { ... }
select *
from departments
where location_id = 1700;

-- public Department getDepartmentById(int departmentId) { ... }
select *
from departments
where department_id = 10;

 

 

 

 

2-2. 구현 방법

 

 

  • User 관련 요구사항 리스트
    • 회원가입 - SAMPLE_USERS 테이블에 새 사용자 정보 저장 작업 (INSERT)
      • 입력정보
        : 사용자아이디, 비밀번호, 이름, 이메일, 전화번호, 성별
      • 출력정보
        : 회원가입 성공/실패 여부 출력
      • 서비스의 메소드 선언부 
        : public void registerUser(User user) { ... }
    • 내 정보 보기 - SAMPLE_USERS 테이블에서 특정 사용자 정보 조회 작업 (SELECT)
      • 입력정보
        : 사용자아이디, 비밀번호
      • 출력정보
        : 사용자 상세정보를 출력
      • 서비스의 메소드 선언부
        : public User getUserInfo(String id, String password) { ... }
    •  내 정보 수정 - SAMPLE_USERS 테이블에서 특정 사용자 정보 수정 작업 (UPDATE)
      • 입력정보
        : 사용자아이디, 비밀번호, 새 비밀번호
      • 출력정보
        : 정보수정 성공/실패 여부 출력
      • 서비스의 메소드 선언부
        : public void updateUserInfo(String id, String oldPassword, String password) { ... }
    •  탈퇴 - SAMPLE_USERS 테이블에서 특정 사용자의 USER_ENABLED를 'N'으로 변경하는 작업 (UPDATE)
      • 입력정보
        : 사용자아이디, 비밀번호
      • 출력정보
        : 회원탈퇴 성공/실패 여부 출력
      • 서비스의 메소드 선언부
        : public void disabledUser(String id, String password) { ... }

 

  • UserService.java의 주요 메소드
    • 회원가입
      • 입력정보
        : 사용자아이디, 비밀번호, 이름, 이메일, 전화번호, 성별
      • 출력정보
        : 회원가입 성공/실패 여부 출력
      • 메소드
        public void registerUser(User user) {
        1. 아이디로 회원정보 조회 - 있으면 예외발생
             select * from sample_users where user_id = ?
        2. 이메일로 회원정보 조회  - 있으면 예외발생
             select * from sample_users where user_email = ?
        3. 회원정보 저장하기
             insert into sample_users (user_id, user_pasword, user_name, user_email, user_tel, user_gender) values (?,?,?,?,?,?)
        }
    • 내 정보 보기
      • 입력정보
        : 사용자아이디, 비밀번호
      • 출력정보
        : 사용자 상세정보를 출력
      • 메소드
        public User getUserInfo(String id, String password) {
        1. 아이디로 회원정보 조회
             select * from sample_users where user_id = ?
        2. 비밀번호가 일치하지 않으면 - 예외발생
        3. 회원정보 제공
        }
    • 내 정보 수정(비밀번호 변경)
      • 입력정보
        : 사용자아이디, 비밀번호, 새 비밀번호
      • 출력정보
        : 정보수정 성공/실패 여부 출력
      • 메소드
        public void updateUserInfo(String id, String oldPassword, String password) {
        1. 아이디로 회원정보 조회
             select * from sample_users where user_id = ?
        2. 비밀번호가 일치하지 않으면 - 예외발생
        3. 회원정보의 비밀번호 변경
             update sample_users set user_password = ? where user_id = ?
        }
    • 회원 탈퇴
      • 입력정보
        : 사용자아이디, 비밀번호
      • 출력정보
        : 회원탈퇴 성공/실패 여부 출력
      • 메소드
        public void disabledUser(String id, String password) {
        1. 아이디로 회원정보 조회
             select * from sample_users where user_id = ?
        2. 비밀번호가 일치하지 않으면 - 예외발생
        3. 회원정보의 enabled를 'N'으로 변경
             update sample_users set user_enabled = 'N' where user_id = ?
        }

 

  • UserDao.java의 주요 메소드
    • select * from sample_users where user_id = ?
      * 입력 - 사용자 아이디 (primary key)
      * 출력 - 사용자정보 하나
      public User getUserById(String id) {
      }

    • select * from sample_users where user_email = ?'
      * 입력 - 사용자 이메일 (unique key
      * 출력 - 사용자정보 하나
      public User getUserByEmail(String email) {
      }

    • insert into sample_users (user_id, user_pasword, user_name, user_email, user_tel, user_gender) values (?,?,?,?,?,?)
      * 입력 - 사용자정보
      * 출력 - 없음
      public void insertUser(User user) {
      }

    • update sample_users set user_password = ? where user_id = ?
      * 입력 - 사용자 아이디, 비밀번호
      * 출력 - 없음
      public void updateUserPassword(String id, String password) {
      }

    • update sample_users set user_enabled = 'N' where user_id = ?
      * 입력 - 사용자 아이디
      * 출력 - 없음
      public void updateUserEnabled(String id) {
      }

 

 

 

2-3. 데이터베이스 액세스를 위한 ibatis 매핑

 

 

* ibatis

- SQL Mapper Framework

- SQL과 객체를 매핑시켜서 데이터베이스 액세스 작업을 수행하는 라이브러리 

 

 

* SQL과 객체 매핑

 

parameterClass : 쿼리실행에 필요한 값을 전해주는 클래스

                              (insert 쿼리실행에 필요한 값을 Product객체에 담아서 전달

                               delete 쿼리실행에 필요한 정수값을 전달

                               update 쿼리실행에 필요한 값을 Product객체에 담아서 전달) 

 

resultClass : 쿼리실행결과 값을 담고있는 클래스 

                      (insert, update, delete에는 필요없음!! select문에서만 필요) 

 

 

어떻게 매핑?

 

 

xml 객체 안에 insert 쿼리문 작성 

parameterClass="com.sample.vo.Product"    ->   Product 객체의 값 전달 

values의 값들                                                       ->   # Product객체 안에 있는 변수명 #

 

 

 

 

 

2-4. 데이터베이스 액세스 작업 '환경설정'

 

 

1. ibatis와 오라클 드라이버를 클래스패스에 추가한다 

    라이브러리

    - ibatis 라이브러리 파일

      : 오른쪽 -> buildpath -> configure build path -> class path -> add jars -> ibatis-sqlmap-2.3.4.726.jar 파일 추가

    - JDBC 드라이버
      : 오른쪽 -> buildpath -> configure build path -> class path -> add external jars -> ojdbc11.jar 파일 추가

 

 

 

2. ibatis용 환경설정파일과 mapper 파일을 저장하는 소스폴더를 추가한다.

   - 프로젝트에 resources 소스폴더를 추가한다.

   - resources 소스폴더 하위에 META-INF 폴더를 추가한다. (META-INF : 부가적인 설정정보가 있는 폴더라는 뜻) 

   - META-INF 폴더 하위에 ibatis 폴더를 추가한다.

 

3. ibatis 환경설정파일 추가하기

   - resources/META-INF/ibatis/ibatis-config.xml 파일을 추가한다. -> source탭 확인

   ( * 주석 : ctrl + shift + / ) 

 

XML 
      - eXtensible Markup Language
      - 확장 가능한 마크업 문서를 작성하는 표준이다. 
         * 확장 가능한 : 사용자가 임의의 태그, 문서작성 규칙을 자유롭게 정의해서 사용할 수 있다. 
         * 마크업 문서를 <태그> 혹은 <태그 속성명="속성값">을 이용해서 작성된 문서
            ( <sqlMap> , <select> : 태그 ,   <select id="getAllUsers"> : 태그 속성명="속성값" ) 

XML 문서의 구조
          - 선언부
                <?xml version="1.0" encoding="UTF-8"?>         
                // XML 문서 선언 -> <xml>을 사용하여 XML문서임을 명시 (xml버전, 인코딩 기본값) 
                <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"   
                       "http://ibatis.apache.org/dtd/sql-map-2.dtd">   
               // 도큐먼트 타입(문서형) 선언 -> 외부 DTD와 XML문서 연결 (작성규칙을 여기서 다운받아라)

           - 바디부
                <sqlMap>                      // Root 엘리먼트(태그) 
                       ~~ // XML 컨텐츠 ~~
                </sqlMap>


HTML
       - Hyper Text Markup Language
       - 링크를 클릭하면 그 링크와 연결된 문서를 열어볼 수 있는 마크업 문서를 작성하는 표준
       - 사용자가 임의로 태그를 생성해서 사용할 수 없다. 
          * 태그의 종류, 태그의 속성, 태그의 작성규칙이 정해져있다.
          * 모든 브라우저는 HTML 표준에 맞게 작성된 HTML문서를 렌더링해서 표현

 

 

 

4. ibatis-config.xml에 데이터베이스 연결정보 설정

  <transactionManager type="JDBC">
        <dataSource type="SIMPLE">
               <property name="JDBC.Driver" value="oracle.jdbc.OracleDriver" />
               <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:xe" />
               <property name="JDBC.Username" value="hr" />
               <property name="JDBC.Password" value="zxcv1234" />
        </dataSource>
   </transactionManager>

 

* JDBC.Driver : 오라클 JDBC 드라이버 클래스의 패키지 경로 및 클래스명

* JDBC.ConnectionURL : jdbc URL

* JDBC.Username : 데이터베이스 사용자 계정명

*JDBC.Password : 데이터베이스 사용자 비밀번호 

 

5. ibatis mapper 파일 등록 

   - resources/META-INF/ibatis/mappers/users.xml 파일을 추가한다. 

 

6. ibatis-config.xml에 mapper파일 (users.xml) 등록 (하나 만들면 그때 하나씩 등록)

   - <sqlMap resource="META-INF/ibatis/mappers/users.xml" />

   - users.xml - 내가 실행할 쿼리를 적는 곳 

 

7. ibatis 헬프 클래스 등록

   - src 폴더에 com.sapmle.util 패키지 생성

   - SqlMapper.java 클래스 추가 

 

   < SqlMapper의 주요 API >

   - INSERT 구문 실행 

      void insert(String id) 

      void insert(String id, Object param)

   - UPDATE 구문 실행 

      void update(String id)

      void update(String id, Object param)

   - DELETE 구문 실행 

      void delete(String id)

      void delete(String id, Object param)

   - SELECT 구문 실행 

      Object selectOne(String id)

      Object selectOne(String id, Object param)

      List<?> selectList(String id)

      List<?> selectList(String id, Object param)

 

 

 

3-3. 데이터베이스 액세스 작업 준비 

 

1. 테이블을 표현하는 VO 클래스 작성

    오라클의 sample_users       ->  자바의 public class User 

    오라클의 sample_products  ->  자바의 public class Product 

 

2. 데이터베이스 액세스 작업을 수행하는 DAO 클래스 작성

    public class UserDao {

 

    }

 

3. SQL과 객체를 매핑하는 매퍼파일 추가 (하나 만들 때마다 추가)

    resources/META-INF/ibatis/mappers/users.xml 파일 추가

    <sqlmap>

 

    </sqlpmap>

 

4. ibatis 환경설정 파일에 매퍼파일 등록  (하나 만들 때마다 하나씩 등록)

    resources/META-INF/ibatis/ibatis-config.xml에 users.xml 파일 등록

    <sqlMap resources="META-INF/ibatis/mappers/users.xml" />

 

 

3-4. 데이터베이스 액세스 작업 구현

 

1. 실행할 데이터베이스 액세스 작업 정의

     ex) 사용자아이디로 사용자 정보 조회하기

 

2. 실행할 SQL 작성

    select *

    from sample_users 

    where user_id = ?

 

3. 파라미터클래스(SQL실행에 필요한 값을 표현하는 클래스)와 리절트클래스(SQL 실행결과를 저장하는 객체의 클래스)를 결정

    parameterClass="string"                           

    ---> SQL 실행에 필요한 값이 "사용자 아이디(String)" 

    resultClass="com.sample.store.vo.User" 

    ---> SQL을 실행하면 사용자정보(아이디, 비밀번호, 이름, 이메일 등)가 조회된다. 그 정보를 모두 담을 수 있는 객체는 User

 

4. 매퍼파일(resources/META-INF/ibatis/mappers/users.xml)에 SQL 구문 정의  

      <select id="getUserById" parameterClass="string" resultClass="com.sample.store.vo.User">
             select 
                         user_id  as id,
                         user_password  as password,
                         user_name  as name, 
                         ... 
             from 
                         sample_users
             where 
                         user_id = #value#
      </select>

 

 

5. DAO 클래스에 xml에서 작성한 SQL 구문을 실행시키는 메소드 정의 (sql 하나당 메소드 만들기!!!) 

    parameterClass="string"이 메소드의 매개변수 타입

    resultClass="com.sample.store.vo.User"가 메소드의 반환타입

    * 단, SQL의 실행결과로 한 행이 조회되는지 여러 행이 조회되는지에 따라서 반환타입이 달라진다.

      ( 한 행이 조회되는 경우(primary key, unique key인 경우)     : User 

        여러 행이 조회되는 경우(pk, uk 이외의 경우)                         : List<User> )

    

    public User getUserById(String userId)  {

           // SqlMapper.selectOne(String sql의 id, Object param) : SELECT구문을 실행하고, Object를 반환

           // selectOne()메소드는 resultClass="com.sample.store.vo.User"에 정의된 객체를 Object로 클래스 형변환된 상태로 반환. 

          User user = (User) SqlMappler.seletOne("getUserById", userId);     

          return user;

    }

 

( UserDao 에서 sqlMapper의 insert메소드 실행 

  이때 "insertUser", user 를 전달해줌 

  -> sqlMapper에서 insert 메소드를 실행하면 sqlMapClient라는 실행엔진을 실행 

  -> 실행엔진에 id = "insertUser", param = User객체 만 xml에 전달해줌 

  -> 실행엔진에서 xml 중에서 id가 "insertUser"인 것을 찾아

  -> id에 해당하는 쿼리를 가져와서 실행 

  -> 실행엔진 내부에서 알아서

      connection 연결, preparedStatement 생성, #변수명# 자리에 User객체에 저장된 값 바인딩, db에 SQL 전송/실행 다함 )

 

 

< 우리가 할 일 >

users.xml에서 sql 작성, 

UserDao 작성 (실행엔진에 id, param만 전달)

 

 

 

< 구현 연습 > 

- 모든 사용자 정보를 조회하기

   - SQL
      select *
      from sample_users
      order by user_id asc

   - parameter/result
      parameterClass : 정의할 필요없음
      resultClass="com.sample.store.vo.User" <--- 사용자 정보(아이디, 비번, 이름, 이메일, 전화 ... 는 User객체에 저장할 수 있다.)가 여러 행 조회된다.

   - SQL 매핑
      <select id="getAllUsers" resultClass="com.sample.store.vo.User">
         select user_id as id,
               user_password as password,
               user_name as name, 
               ...
         from sample_users
         order by user_id asc
      </select>

   - DAO클래스에 메소드 정의
      public List<User> getAllUsers( ) {
          List<User> users = (List<User>) SqlMapper.selectList("getAllUser");
          return users;
      }

 

- 회원가입한 모든 사용자 수를 조회하기 ( 사용자 수 = 하나의 행, 하나의 열 (int타입) 이 나옴! )

   - SQL
            select count(*)
            from sample_users

   - parameter/result
            parameterClass : 필요없음
            resultClass="java.lang.Integer" 혹은 resultClass="int" <--- 사용자 숫자(정수)가 한 행 조회된다.

   - SQL 매핑
            <select id="getUsersCount" resultClass="int">
                   select count(*)             <!-- 값이 딱 하나만 조회되는 경우, 컬럼에 대한 별칭을 적을 필요없다. 
                   from sample_users    (resultClass의 타입을 해당 값의 타입에 맞게 string, int, long, double 중에서 하나를 적으면 된다.)  -->
            </select>

   - DAO클래스에 메소드 정의
              public int getUsersCount( ) {
                     int counts = (Integer) SqlMapper.selectOne("getUsersCount");
                     return counts;
              }

 

- 회원정보 추가하기

   - SQL
               insert into sample_users(user_id, user_password, user_name, user_email, user_tel, user_gender)
               values (?, ?, ?, ?, ?, ?)

   - parameter/result
               parameterClass="com.sample.store.vo.User" <--- 사용자 정보(아이디, 비번, 이름, 이메일, 전화 ... )를 전부 담아서 제공할 수 있는 객체는 User객체다.
               resultClass : INSERT 구문에서는 사용하지 않는다.

   - SQL 매핑
            <insert id="insertUser" parameterClass="com.sample.store.vo.User">
                    insert into sample_users
                           (user_id, user_password, user_name, user_email, user_tel, user_gender) 
                    values 
                          (#id#, #password#, #name#, #email#, #tel#,  #gender#) <!-- User객체의 변수명과 매핑시킨다. -->
           </insert>

   - DAO클래스에 메소드 정의
         public void insertUser(User user) {
             sqlMapper.insert("insertUser", user); // SQL 실행에 필요한 정보가 들어있는 User 객체를 ibatis에게 전달함
}

(DAO에서 User객체를 파라미터로 전달하면, 파리미터에 User객체가 저장되고, xml에서 SQL에서 파라미터로 전달받은 User객체를 가지고 SQL쿼리를 실행시킴 -> insert 쿼리를 실행) 

 

- 회원정보 수정하기

   - SQL
            update sample_users
            set
                    user_password = ?,
                    user_tel = ?,
                    user_point = ?,
                    user_enabled = ?
                    user_updated = sysdate
            where user_id = ?

   - parameter/result
            parameterClass="com.sample.store.vo.User"    (변경가능한 것들을 모아서 객체로 전달)
            resultClass : UPDATE 구문에서는 사용하지 않는다.

   - SQL  매핑
         <update id="updateUser" parameterClass="com.sample.store.vo.User">
                update sample_users
                set
                      user_password = #password#,
                      user_tel = #tel#,
                      user_point = #point#,
                      user_enabled = #enabled#,
                      user_updated_date = sysdate
               where user_id = #id#
        </update>

   - DAO클래스에 메소드 정의
         public void updateUser(User user) {
              SqlMapper.update("updateUser", user)
          }

 

- 사용자이름으로 사용자 조회하기

   - SQL
           select *
           from sample_users
           where user_name = ?  // primary key, unique 제약조건이 지정되지 않은 컬럼이 조건식에 사용되면 항상 여러 행 조회될 수도 있다는 점 항상 생각하기! 

   - parameter/result
            parameter: string
            result : List<User>

   - SQL 매핑
         <select id="getUserByName" parameterClass="string" resultClass="com.sample.store.vo.User">
              select
                     user_id                as id,
                     user_password   as password,
                     user_name         as name, 
                     ... 
              from sample_users
              where user_name = #value#
         </select>

   - DAO클래스에 메소드 정의
        public List<User> getUserByName(String name) {
            List<User> users = (List<User>) SqlMapper.selectList("getUserByName", name);
            return users; 
        } 

 

- 상품번호로 상품 정보 조회하기 

   - SQL
         select *
         from sample_products
         where product_no = ?      ( primary key -> 한 행만 조회됨 ) 

   - parameter/result
         parameterClass : "int"
         resultClass="com.sample.store.vo.Product" 

   - SQL 매핑
         <select id="getProductByNo" parameterClass="int" resultClass="com.sample.store.vo.Product">
              select product_no               as no,
                         product_name         as name,
                         product_maker        as maker, 
                         ...
              from sample_products
              where product_no = #value#
         </select>

   - DAO클래스에 메소드 정의
         public Product getProductByNo(int productNo) {
                Product product = (Product) SqlMapper.selectOne("getProductByNo", productNo);
                return product;
         }

 

- 상품이름으로 상품정보 조회하기

   - SQL
       select *
       from sample_products
       where product_name like '%' || ? || '%'       // pk, uk 제약조건이 없기 때문에 여러개 가능, 이름은 보통 이렇게 검색

   - parameter/result
        parameterClass : "string"
        resultClass="com.sample.store.vo.Product" 

   - SQL 매핑
        <select id="getProductByName" parameterClass="string" resultClass="com.sample.store.vo.Product">
                   select 
                              product_no            as no, 
                              product_name       as name, 
                              product_maker      as maker, 
                              ... 
                    from sample_products
                    where product_name like '%' ||  #value# || '%'
        </select>

   - DAO클래스에 메소드 정의
        public List<Product> getProductByName(String name) { 
                 List<Product> products = (List<Product>) SqlMapper.selectList("getProductByName", name);
                 return products;
        }

 

- 모든 상품정보 조회하기 

   - SQL
        select *
        from sample_products
        order by product_no desc

   - parameter/result
        parameterClass :  없음
        resultClass="com.sample.store.vo.Product"    // 여러개

   - SQL 매핑
        <select id="getAllProducts" resultClass="com.sample.store.vo.Product">
                   select 
                              product_no            as no, 
                              product_name       as name, 
                              product_maker      as maker, 
                              ... 
                    from sample_products
                    order by product_no desc
        </select>

   - DAO클래스에 메소드 정의
        public List<Product> getAllProducts( ) { 
                 List<Product> products = (List<Product>) SqlMapper.selectList("getAllProducts");
                 return products;
        }

 

- 새 상품정보 저장하기 

   - SQL (디폴트 값이 없는 애들을 적어주면 됨)
        insert into sample_products 
                      (product_no, product_name, product_maker, product_price, product_discount_rate, product_stock)
        values
                      ( sample_products_seq.nextval, ?, ?, ?, ?, ?, ? ) 
      
   - parameter/result
        parameterClass : "com.sample.store.vo.Product"
        resultClass=없음

   - SQL 매핑
        <insert id="insertProduct" parameterClass="com.sample.store.vo.Product">
                   insert into sample_product
                       (product_no, product_name, product_maker, product_price, product_discount_rate, product_stock)
                   values
                        (sample_products_seq.nextval, #name#, #maker#, #price#, #discountRate#, #productStock#) 
        </insert>

   - DAO클래스에 메소드 정의
      public void insertProduct(Product product) {
                SqlMapper.insert("insertProduct", product);
      }

 

- 최소가격, 최대가격 범위내의 상품정보 조회하기 

   - SQL 
        select *
        from sample_products
        where product_price >= ? and product_price <= ?      -> pk, uk가 아니기 때문에 여러개 조회 가능 
        order by product_price asc
      
   - parameter/result
        parameterClass : "map
        resultClass="com.sample.store.vo.Product"

   - SQL 매핑
        <select id="getProductByPrice parameterClass="map" resultClass="com.sample.store.vo.Product">
              select  product_no         as no,
                          product_name   as name, 
                          product_maker  as maker, 
                          ... 
              from sample_products
              where product_price >= #minPrice# and product_price <= #maxPrice#
              order by product_price asc
        </select>

( * 자바의 SQL 안에는 <, >로 대소 비교 못함! 
 1)      &lt;     (= &lessthan) 
 2)      <![CDATA[   ~~~  ]]>  로 sql문 감싸기


   - DAO클래스에 메소드 정의
         public List<Product> getProductByPrice(Map<String, Object> param) {
                 List<Product> products = (List<Products>) SqlMapper.selectList("getProductByPrice", param);
                 return products
         } 


* 가격으로 검색하기 사용
  Controller를 통해서 사용자로부터 최소가격, 최대가격을 입력받고,
  service클래스의 searchProducts 메소드로  전달
  searchProducts메소드로 받은 값들을 map의 key값의 value값으로 넣음

    StoreController.java
        public void 가격검색( ) {
           최소가격을 입력하세요
           int min = keyboard.getInt();
           최대가격을 입력하세요
           int max = keyboard.getInt();

           List<Product> products = productService.searchProducts(min, max);
           for (Product product : products) {
               출력
           }
        } 

   ProductService.java
      public List<Product> searchProducts(int minPrice, int maxPrice) {
         Map<String, Object> map = new HashMap<>();
         map.put("minPrice", minPrice);
         map.put("maxPrice", maxPrice);
         
         List<Product> products = productDao.getProductsByPrice(map);

         return products;
      }

 

 

 

 

** update 실행 **

 

 

 

** update 실행 **


1.수정할 사용자 정보를 반드시 먼저 조회

2. 사용자 정보 체크 로직 수행 ( 아이디, 비밀번호 일치하는지 )

3. 정보 변경
user.setPassword(password);      // 비밀번호 바꾸는 작업

4. 변경된 정보가 반영된 User객체를 UserDao에 전달해서 객체 업데이트
user객체를 userDao.updateUser(user); 로 전달하면 
-> dao 에서 updateUser 메소드를 실행하면서 식별 id를 통해서 xml에서 해당 id에 해당하는 xml문을 찾아서 실행
-> user 객체가 결국 xml의 파라미터 User 객체로 전달됨

=> update쿼리를 각각마다 만들지 X ! 변경가능한 모든 것들을 그냥 객체로 만들어서 줌 

 

 

 

 

3-3 연습하기

 

- User 객체 만들기 (오라클의 sample_users의 내용)

 

- ibatis-config.xml 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
 
<sqlMapConfig>
 
 	<!-- 데이터베이스 연결 정보 설정  -->
	<transactionManager type="JDBC">
		<dataSource type="SIMPLE">
			<property name="JDBC.Driver" value="oracle.jdbc.OracleDriver" />
			<property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:xe" />
			<property name="JDBC.Username" value="hr" />
			<property name="JDBC.Password" value="zxcv1234" />
		</dataSource>
	</transactionManager>
 
 	<!-- SQL 매퍼 파일 등록 -->
 	<sqlMap resource="META-INF/ibatis/mappers/users.xml" />
<!--  
 	<sqlMap resource="META-INF/ibatis/mappers/products.xml" />
 	<sqlMap resource="META-INF/ibatis/mappers/cartItems.xml" />
 	<sqlMap resource="META-INF/ibatis/mappers/orders.xml" />
 	<sqlMap resource="META-INF/ibatis/mappers/orderItems.xml" />
 	<sqlMap resource="META-INF/ibatis/mappers/reviews.xml" />
 	<sqlMap resource="META-INF/ibatis/mappers/pointHistories.xml" /> -->
	

</sqlMapConfig>

 

-SqlMapper.java

package com.sample.util;

import java.io.Reader;
import java.sql.SQLException;
import java.util.List;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

/**
 * ibatis 프레임워크를 사용한 데이터베이스 엑세스 작업을 지원하는 헬프 클래스다.
 * @author lee_e
 *
 */
public class SqlMapper {

	private static SqlMapClient sqlMapClient;
	static {
		try {
			Reader reader = Resources.getResourceAsReader("META-INF/ibatis/ibatis-config.xml");
			sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	private static SqlMapClient getSqlMapClient() {
		return sqlMapClient;
	}
	
	/**
	 * 지정된 아이디에 해당하는 매핑된 SQL 구문을 실행, INSERT 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 */
	public static void insert(String id) {
		try {
			getSqlMapClient().insert(id);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	} 
	
	/**
	 * 아이디와 파라미터객체를 전달받아서 매핑된 SQL 구문을 실행, INSERT 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @param param SQL 구문 실행에 필요한 값을 가지고 있는 파라미터 객체
	 */
	public static void insert(String id, Object param) {
		try {
			getSqlMapClient().insert(id, param);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	/**
	 * 지정된 아이디에 해당하는 매핑된 SQL 구문을 실행, UPDATE 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 */
	public static void update(String id) {
		try {
			getSqlMapClient().update(id);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	} 
	
	/**
	 * 아이디와 파라미터객체를 전달받아서 매핑된 SQL 구문을 실행, UPDATE 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @param param SQL 구문 실행에 필요한 값을 가지고 있는 파라미터 객체
	 */
	public static void update(String id, Object param) {
		try {
			getSqlMapClient().update(id, param);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	/**
	 * 지정된 아이디에 해당하는 매핑된 SQL 구문을 실행, DELETE 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 */
	public static void delete(String id) {
		try {
			getSqlMapClient().delete(id);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	} 
	
	/**
	 * 아이디와 파라미터객체를 전달받아서 매핑된 SQL 구문을 실행, DELETE 작업을 수행시킨다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @param param SQL 구문 실행에 필요한 값을 가지고 있는 파라미터 객체
	 */
	public static void delete(String id, Object param) {
		try {
			getSqlMapClient().delete(id, param);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	/**
	 * 지정된 아이디에 해당하는 매핑된 SQL 구문을 실행, SELECT 작업을 수행시킨다.
	 * <P>조회 결과를 Object 객체로 반환한다.
	 * <P>조회 결과가 하나도 없으면 null을 반환한다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @return 조회결과가 저장된 객체
	 */
	public static Object selectOne(String id) {
		try {
			return getSqlMapClient().queryForObject(id);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	} 
	
	/**
	 * 아이디와 파라미터객체를 전달받아서 매핑된 SQL 구문을 실행, SELECT 작업을 수행시킨다.
	 * <P>조회 결과를 Object 객체로 반환한다.
	 * <P>조회 결과가 하나도 없으면 null을 반환한다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @param param SQL 구문 실행에 필요한 값을 가지고 있는 파라미터 객체
	 * @return 조회결과가 저장된 객체
	 */
	public static Object selectOne(String id, Object param) {
		try {
			return getSqlMapClient().queryForObject(id, param);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	/**
	 * 지정된 아이디에 해당하는 매핑된 SQL 구문을 실행, SELECT 작업을 수행시킨다.
	 * <P>조회 결과를 List 객체로 반환한다.
	 * <P>조회 결과가 하나도 없으면 빈 List 객체를 반환한다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @return List 객체
	 */
	public static List<?> selectList(String id) {
		try {
			return getSqlMapClient().queryForList(id);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	} 
	
	/**
	 * 아이디와 파라미터객체를 전달받아서 매핑된 SQL 구문을 실행, SELECT 작업을 수행시킨다.
	 * <P>조회 결과를 List 객체로 반환한다.
	 * <P>조회 결과가 하나도 없으면 빈 List 객체를 반환한다.
	 * @param id 매핑된 SQL 구문의 아이디
	 * @param param SQL 구문 실행에 필요한 값을 가지고 있는 파라미터 객체
	 * @return List 객체
	 */
	public static List<?> selectList(String id, Object param) {
		try {
			return getSqlMapClient().queryForList(id, param);
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}
	
	
	
}

 

- users.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" 
	"http://ibatis.apache.org/dtd/sql-map-2.dtd">
 
<sqlMap>
 	<!-- 사용자 정보 insert -->
 	<!-- 
 		<insert />
 			INSERT SQL 구문을 정의한다.
		id="insertUser"
			이 SQL구문을 식별하기 위한 아이디값을 지정한다.
		parameterClass="com.sample.vo.User"
			이 SQL구문 실행에 필요한 값을 가져올 객체의 타입을 지정한다. (User객체와 아래SQL을 매핑)
			이 SQL구문 실행에 필요한 사용자정보는 User 객체로 전달받는다. 
		#변수명#
			parameterClass로 지정한 객체의 변수명을 적는다.
			해당 객체의 변수에 저장된 값이 #변수명#에 전달된다.
 	 -->
 	<insert id="insertUser" parameterClass="com.sample.vo.User">
 		insert into sample_users 
 		(user_id, user_password, user_name, user_email, user_tel, user_gender)
 		values
 		(#id#, #password#, #name#, #email#, #tel#, #gender#)
 	</insert>
 	
 	<!-- 
 		<delete />
 			DELETE SQL 구문을 정의한다.
		id="deleteUser"
			이 SQL구문을 식별하기 위한 아이디값을 지정한다.
		parameterClass="string"
			이 SQL구문 실행에 필요한 값은 문자열타입의 값이다. 
		#value#
			parameterClass의 타입이 VO객체나 MAP객체가 아니라 문자열, 정수, 실수 일 때 사용한다. 
			#value# 위치에 해당 값이 바인딩된다.
			SQL 실행시 필요한 값이 오직 하나일 때 사용한다. 
 	 -->
 	<delete id="deleteUser" parameterClass="string">	<!-- string은 java.lang.String에 대한 별칭 -->
 		delete from sample_users
 		where user_id = #value#
 	</delete>
 	
 	<!-- 
 		<select />
 			SELECT SQL 구문을 정의한다.
		id="getAllUsers"
			이 SQL구문을 식별하기 위한 아이디값을 지정한다.
		resutlClass="com.sample.vo.User"
			이 SQL구문 실행 후 조회된 데이터를 저장할 객체의 클래스 타입을 지정한다.
			resultClass에서 지정하는 클래스 타입은 행 하나를 어느 객체에 담을 것인지 지정하는 것이다. ( List는 절대로 안됨. User객체의 한 행씩만 담음 ) 
			조회결과(ResultSet) 핸들링
				1. ibatis 엔진은 SQL 구문을 실행한 후, resultClass에 지정된 클래스로 객체를 생성한다.
				2. ibatis 엔진은 1번에서 생성한 객체에 값을 저장할 때, 컬럼명과 동일한 이름의 변수에 값을 저장한다. 
					* 컬럼명과 변수명이 서로 다르면 컬럼명을 변수이름과 같은 이름의 별칭으로 지정한다. 
		
		*** SELECT 구문의 실행결과 여러 행이 획득되는 경우
			List SqlMapper.selectList(String id)
			List SqlMapper.selectList(String id, Object param)으로 이 SQL 구문을 실행한다.
			* List 객체를 생성한 다음 조회된 행의 개수만큼 resultClass에 지정된 객체를 생성해서 값을 담고, 그 객체를 List에 저장시키고, List를 반환한다. 
			* 조회된 행이 하나도 없으면 길이가 0인 List객체가 반환된다. (결코 null이 반환되지 않는다.)
			
		*** SELECT 구문의 실행결과가 언제나!! 한 행만 획득되는 경우
			Obejct SqlMapper.selectOne(String id)
			Object SqlMapper.selectOne(String id, Object param)으로 이 SQL 구문을 실행한다.
			* resultClass에 지정된 객체를 생성해서 값을 담고, 그 객체를 반환한다.
			* 조회된 행이 하나도 없으면 null이 반환된다. 
            		* Object 타입이니까 형변환 필요 
 		
	 -->
 	<select id="getAllUsers" resultClass="com.sample.vo.User">
 		select user_id				as id,
 				user_password		as password,
 				user_name		as name, 
 				user_email		as email,
 				user_gender		as gender,
 				user_point		as point,
 				user_enabled		as enabled,
 				user_created_date	as createdDate,
 				user_updated_date	as updatedDate
 		from sample_users
 		order by user_id asc
 	</select>
 	
 	<select id="getUserById" parameterClass="string" resultClass="com.sample.vo.User">	<!-- 컬럼의 이름과 user객체의 변수명이 같아야함 -->
 		select user_id				as id,
 				user_password		as password,
 				user_name		as name, 
 				user_email		as email,
 				user_gender		as gender,
 				user_point		as point,
 				user_enabled		as enabled,
 				user_created_date	as createdDate,
 				user_updated_date	as updatedDate
 		from sample_users
 		where user_id = #value# 
 	</select>
</sqlMap>

 

- UserDao 

package com.sample.dao;

import java.util.List;

import com.sample.util.SqlMapper;
import com.sample.vo.User;

public class UserDao {

	public void insertUser(User user) {
		SqlMapper.insert("insertUser", user);	// "users.xml의 구문식별 id입력", User객체를 users.xml로 전달 
	}
	
	public void deleteUserById(String userId) {
		SqlMapper.delete("deleteUser", userId);
	}
	
	@SuppressWarnings("unchecked")
	public List<User> getAllUsers(){
		List<User> users = (List<User>) SqlMapper.selectList("getAllUsers");
		return users;
	}
	
	public User getUserById(String userId) {
		User user = (User) SqlMapper.selectOne("getUserById", userId);
		return user;
	}
}

 

-App1 (insert기능)

package com.sample;

import com.sample.dao.UserDao;
import com.sample.vo.User;

public class App1 {

	public static void main(String[] args) {
		UserDao userDao = new UserDao();
		
		User user = new User();
		user.setId("jun");
		user.setPassword("zxcv1234");
		user.setName("김준희");
		user.setEmail("jun@naver.com");
		user.setTel("010-1111-2222");
		user.setGender("여");
		
		userDao.insertUser(user);
	}
}

 

-App2 (delete 기능) 

package com.sample;

import com.sample.dao.UserDao;

public class App2 {

	public static void main(String[] args) {
		UserDao userDao = new UserDao();
		
		userDao.deleteUserById("jun");
	}
}

 

-App3 (select 기능)

package com.sample;

import java.util.List;

import com.sample.dao.UserDao;
import com.sample.vo.User;

public class App3 {
	
	public static void main(String[] args) {
		
		UserDao userDao = new UserDao();
		
		System.out.println("### 모든 사용자 정보 조회");
		List<User> users = userDao.getAllUsers();
		for(User user : users) {
			System.out.println(user.getId() + ", " + user.getName() + ", " + user.getEmail());
		}
		
		System.out.println("### 아이디로 사용자 정보 조회");
		User user = userDao.getUserById("kim");
		System.out.println(user.getId() + ", " + user.getName() + ", " + user.getEmail());
	}

}