[2022.10.26.수] ibatis, 자바로 데이터베이스 액세스
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) { ... }
- 입력정보
- 회원가입 - SAMPLE_USERS 테이블에 새 사용자 정보 저장 작업 (INSERT)
- 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) {
}
- select * from sample_users where user_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) < (= &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());
}
}