MyBatis 설정
/mybatis.config
#{something} = "a"
⇒ ProductVO.setSomething("a")
* CDATA Section : Character Data 아래 영역은 xml tag가 아니라 SQL 문자임을 알려준다.
/product.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Sql Mapper (MyBatis Mapper) -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 설정 -->
<mapper namespace="product">
<sql id="selectProduct">
<!-- product_no as productNO
: SQL의 column명과 productVO의 instance 변수명이 일치하지 않을 경우,
SQL에서 별칭으로 productVO의 instance 변수명을 기준으로 명시하면 됨
-->
SELECT product_no as productNO, name, maker, price
FROM spring_product
</sql>
<select id="getTotalProductCount" resultType="int">
SELECT COUNT(*)
FROM spring_product
</select>
<select id="getMakerKindList" resultType="string">
SELECT DISTINCT(maker)
FROM spring_product
</select>
<!-- resultType="productVO"
: spring-config.xml에서 typeAliasesPackage를 통해 준 별칭 -->
<select id="getAllProductListOrderByPriceDesc" resultType="productVO">
<include refid="selectProduct"></include>
ORDER BY price DESC
</select>
<select id="findProductByNo" resultType="productVO" parameterType="string">
<include refid="selectProduct"></include>
WHERE product_no = #{value}
</select>
<select id="findProductListByMakerAndPrice" resultType="productVO"
parameterType="productVO">
<include refid="selectProduct"></include>
WHERE maker=#{maker} AND price > #{price}
</select>
<!-- CDATA : Character Data 아래 영역은 xml tag가 아니라 SQL 문자임을 알려준다.
- 비교연산자로 < 를 쓸 때면, xml 태그로 인식하여,
'add child'>'CDATA Section'을 통해 '<'가 들어간 쿼리 줄을 안에 넣어줌 -->
<select id="findProductListByPrice" resultType="productVO" parameterType="int">
<include refid="selectProduct"></include>
<![CDATA[
WHERE price < #{value}
]]>
</select>
<select id="getProductListByGroupByMaker" resultType="map">
SELECT MAKER, COUNT(*) AS TOTAL_COUNT, MAX(price) AS MAX_PRICE
FROM spring_product
GROUP BY MAKER
</select>
<!-- LIKE를 사용 -->
<select id="findProductListLikeName" resultType="productVO" parameterType="string">
<include refid="selectProduct"></include>
WHERE name LIKE '%' || #{value} || '%'
</select>
<!-- INSERT -->
<insert id="registerProduct" parameterType="productVO">
INSERT INTO spring_product(product_no, name, maker, price)
VALUES(spring_product_seq.nextval, #{name}, #{maker}, #{price})
</insert>
<!--
상품 등록 시점에 미리 상품 번호(product_no)를 시퀀스로 생성하여,
productVO의 productNo 변수에 할당하여,
spring_product table에 INSERT한다!
-->
<insert id="registerProductVer2" parameterType="productVO">
<!-- productVO 객체의 productNo에 nextval을 할당해준다. -->
<selectKey keyProperty="productNo" resultType="string" order="BEFORE">
SELECT spring_product_seq.nextval
FROM dual
</selectKey>
INSERT INTO spring_product(product_no, name, maker, price)
VALUES(#{productNo}, #{name}, #{maker}, #{price})
</insert>
</mapper>
Spring 설정
1) DBCP 정의
2) MyBatis와 Spring 연동 설정
- SqlSessionFactory 생성 (DBCP(datebase connection pool) 주입 *factory : DBCP와 SQL 정보가 들어있다.
- MyBatis에서 쓸 mapper location(path) 주입
3) typeAliasesPackage(패키지 별칭 타입) 설정 ex) org.kosta.model.vo.MemberVO -> memberVO
(패키지 아래의 클래스는 모두 자동으로 소문자로 시작하는 클래스명으로 별칭을 주도록 설정)
4) MyBatis와 Spring 연동 시, 생산성을 위해 SqlSessionTemplate 클래스 이용
- 생성자로 SqlSessionFactory 주입
- 개발 생산성을 위해 SqlSessionTemplate 클래스를 이용, SqlSessionTemplate은 선언적 방식의 트랜잭션 제어를 지원
(= AOP 기반 Transaction 제어)
5) DAO bean 생성 (template을 생성자로!)
/spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- DBCP 정의 -->
<bean id="dbcp" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:xe"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- MyBatis와 Spring 연동 설정-->
<!-- 1. sqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- DBCP(datebase connection pool) 주입 -->
<property name="dataSource" ref="dbcp"/>
<!-- MyBatis에서 쓸 mapper loation(path) 주입 -->
<property name="mapperLocations" value="classpath:/mybatis/config/*.xml"/>
<!-- Package에 별칭주기 :
org.kosta.model.vo 패키지 아래의 클래스는
모두 자동으로 소문자로 시작하는 클래스명으로 별칭을 주도록 설정
ex) org.kosta.model.ProductVO 는 productVO로! -->
<property name="typeAliasesPackage" value="org.kosta.model.vo"/>
</bean>
<!-- 2. 개발 생산성을 위해 SqlSessionTemplate 클래스를 이용
SqlSessionTemplate은 선언적 방식의 트랜잭션 제어를 지원
(= AOP 기반 Transaction 제어) -->
<bean id="SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactoryBean"/>
</bean>
<!-- 3. DAO 생성
: productDAOImpl bean 생성
- 생성 시에 생성자에 SqlSessionTemplate을 DI한다-->
<bean id="productDAO" class="org.kosta.model.dao.ProductDAOImpl">
<constructor-arg ref="SqlSessionTemplate"/>
</bean>
</beans>
SQL
1. spring_product TABLE 생성
CREATE TABLE spring_product(
product_no NUMBER PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
maker VARCHAR2(100) NOT NULL,
price NUMBER NOT NULL
)
-- 시퀀스 생성
CREATE SEQUENCE spring_product_seq;
2. 테이블에 값 INSERT
INSERT INTO SPRING_PRODUCT VALUES (spring_product_seq.nextVAL, '바나나우유', '바나공장', 3000);
INSERT INTO SPRING_PRODUCT VALUES (spring_product_seq.nextVAL, '그릭요거트', '발효발효', 2500);
INSERT INTO SPRING_PRODUCT VALUES (spring_product_seq.nextVAL, '딸기요거트', '발효발효', 1500);
INSERT INTO SPRING_PRODUCT VALUES (spring_product_seq.nextVAL, '바나나크림치즈', '바나공장', 2000);
INSERT INTO SPRING_PRODUCT VALUES (spring_product_seq.nextVAL, '바나칩', '바나공장', 300);
> spring_product TABLE
/org.kosta.model.vo
ProductVO는 spring-config.xml에서
<property name="typeAliasesPackage" value="org.kosta.model.vo"/> 로 설정하여,
소문자로 시작하는 productVO로 별칭이 정해진다.
/ProductVO.java
package org.kosta.model.vo;
/*
* ProductVO는 Spring-config.xml에서
* <property name="typeAliasesPackage" value="org.kosta.model.vo"/> 로 설정하여,
* 소문자로 시작하는 productVO로 별칭이 정해진다.
*/
public class ProductVO {
private String productNo; //실제 DB 컬럼명은 product_no로 일치하지 않는다.
/* product.xml에서 SQL과 productVO의 변수명을 일치시키기 위해,
* (product.xml에서는 productVO.set[변수명]으로 값을 주입함)
* SQL문의 column명의 별칭을 productVO의 인스턴스 변수명을 기준으로 명시해준다.
*/
private String name;
private String maker;
private int price ;
public ProductVO() {
super();
}
public ProductVO(String name, String maker, int price) {
super();
this.name = name;
this.maker = maker;
this.price = price;
}
public ProductVO(String productNo, String name, String maker, int price) {
super();
this.productNo = productNo;
this.name = name;
this.maker = maker;
this.price = price;
}
public String getProductNo() {
return productNo;
}
public void setProductNo(String productNo) {
this.productNo = productNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMaker() {
return maker;
}
public void setMaker(String maker) {
this.maker = maker;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "ProductVO [productNo=" + productNo + ", name=" + name + ", maker=" + maker + ", price=" + price + "]";
}
}
/org.kosta.model.dao
/ProductDAO.java <<interface>>
package org.kosta.model.dao;
import java.util.List;
import java.util.Map;
import org.kosta.model.vo.ProductVO;
/*
* ProductDAOImpl의 method의 추상 메서드가 있음
* (ProductDAOImpl가 override할 method)
*/
public interface ProductDAO {
int getTotalProductCount();
List<String> getMakerKindList();
List<ProductVO> getAllProductListOrderByPriceDesc();
ProductVO findProductByNo(String productNo);
List<ProductVO> findProductListByMakerAndPrice(ProductVO pvo);
List<ProductVO> findProductListByPrice(int price);
List<Map<String, Object>> getProductListByGroupByMaker();
List<ProductVO> findProductListLikeName(String word);
void registerProduct(ProductVO paramVO);
void registerProductVer2(ProductVO paramVO);
}
/ProductDAOImpl.java
package org.kosta.model.dao;
import java.util.List;
import java.util.Map;
import org.kosta.model.vo.ProductVO;
import org.mybatis.spring.SqlSessionTemplate;
public class ProductDAOImpl implements ProductDAO {
//dbcp, sqlSessionFactoryBean 정보를 모두 담고 있는 SqlSessionTemplate 가져오기
// sqlSessionFactoryBean : sqlSession생성
// sqlSession : SQL 쿼리문 실행
private SqlSessionTemplate template;
//spring-config.xml으로부터 DI(주입)를 생성자로 설정한다.
public ProductDAOImpl(SqlSessionTemplate template) {
super();
this.template = template;
}
// getTotalProductCount : 총 상품 수 반환 메서드
@Override
public int getTotalProductCount() {
return template.selectOne("product.getTotalProductCount");
}
// getMakerKindList : maker 종류 리스트 반환 메서드
@Override
public List<String> getMakerKindList() {
return template.selectList("product.getMakerKindList");
}
// getAllProductListOrderByPriceDesc
// : 가격 내림차순으로 상품 정보 리스트 반환 메서드
@Override
public List<ProductVO> getAllProductListOrderByPriceDesc() {
return template.selectList("product.getAllProductListOrderByPriceDesc");
}
// findProductByNo : productNo로 상품정보 반환 메서드
@Override
public ProductVO findProductByNo(String productNo) {
return template.selectOne("product.findProductByNo", productNo);
}
//findProductListByMakerAndPrice : maker과 price로 상품 정보 리스트로 반환 메서드
@Override
public List<ProductVO> findProductListByMakerAndPrice(ProductVO paramVO) {
return template.selectList("product.findProductListByMakerAndPrice", paramVO);
}
//findProductListByPrice : price로 상품 정보 리스트로 반환 메서드
@Override
public List<ProductVO> findProductListByPrice(int price) {
return template.selectList("product.findProductListByPrice", price);
}
//getProductListByGroupByMaker : 제조사별 상품수, 최고가 조회
@Override
public List<Map<String, Object>> getProductListByGroupByMaker() {
// selectList 하면 자동으로,
// List의 각 값이 Map으로 변환되며,
// column 명이 Map의 key로, 값이 Map의 value(Object)로 들어간다.
return template.selectList("product.getProductListByGroupByMaker");
}
//findProductListLikeName : 이름에 'word'요소가 들어가는 상품 정보 리스트로 반환 메서드
@Override
public List<ProductVO> findProductListLikeName(String word) {
return template.selectList("product.findProductListLikeName", word);
}
//registerProduct: 새로운 productVO INSERT 하기
@Override
public void registerProduct(ProductVO paramVO) {
template.insert("product.registerProduct", paramVO);
}
//registerProductVer2: 상품 등록 시, 등록한 상품의 상품 번호 조회하기
@Override
public void registerProductVer2(ProductVO paramVO) {
template.insert("product.registerProductVer2", paramVO);
}
}
/test
/TestSpringMyBatis.java
package test;
import java.util.List;
import java.util.Map;
import org.kosta.model.dao.ProductDAO;
import org.kosta.model.vo.ProductVO;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpringMyBatis {
public static void main(String[] args) {
ClassPathXmlApplicationContext factory
= new ClassPathXmlApplicationContext("spring-config.xml");
ProductDAO productDAO = (ProductDAO) factory.getBean("productDAO");
// 1. 총 상품 수
System.out.println("** 1. spring과 연동 테스트 - 총 상품 수 : "
+ productDAO.getTotalProductCount() + " **");
// 2. maker 종류를 리스트로 반환
System.out.println("\n** 2. maker 종류를 리스트로 반환 **");
List<String> list = productDAO.getMakerKindList();
for (String maker:list) {
System.out.println(maker);
}
// 3. 가격 내림차순으로 product 정보 반환
System.out.println("\n** 3. 가격 내림차순으로 product 정보 반환 **");
List<ProductVO> list2 = productDAO.getAllProductListOrderByPriceDesc();
for (ProductVO vo:list2)
System.out.println(vo);
// 4. productNo로 상품정보 반환
System.out.println("\n** 4. productNo로 상품정보 반환 **");
String productNo = "1";
ProductVO pvo = productDAO.findProductByNo(productNo);
System.out.println(pvo);
// 5. maker가 '바나공장'이고, price가 1000을 초과하는 상품정보 반환
System.out.println("\n** 5. maker가 '바나공장'이고, price가 1000을 초과하는 상품정보 반환 **");
String maker = "바나공장";
int price = 1000;
ProductVO paramVO = new ProductVO(null, null, maker, price);
List<ProductVO> list3 = productDAO.findProductListByMakerAndPrice(paramVO);
for(ProductVO vo:list3)
System.out.println(vo);
// 6. price가 2000 미만은 상품정보 반환
System.out.println("\n** 6. price가 2000 미만은 상품정보 반환 **");
int price2 = 2000;
List<ProductVO> list4 = productDAO.findProductListByPrice(price2);
for (ProductVO vo:list4)
System.out.println(vo);
// 7. 상품정보 조회 : maker 별 상품 수, 최고가 조회
System.out.println("\n** 7. 제조사별 상품수, 최고가 조회 **");
List<Map<String, Object>> list5 = productDAO.getProductListByGroupByMaker();
for (int i = 0; i < list5.size(); i++) {
Map<String, Object> map = list5.get(i);
System.out.println(map.get("MAKER") + " " + map.get("TOTAL_COUNT")
+ " " + map.get("MAX_PRICE"));
}
// 8. 이름에 word가 들어가는 상품 정보 조회
System.out.println("\n** 8. 이름에 word가 들어가는 상품 정보 조회 **");
String word = "요거트";
List<ProductVO> list6 = productDAO.findProductListLikeName(word);
for (ProductVO vo:list6)
System.out.println(vo);
// 9. 상품 정보를 새로 INSERT 해보기
System.out.println("\n** 9. 상품 정보를 새로 INSERT 해보기 **");
productDAO.registerProduct(new ProductVO("요거트케이크", "발효발효", 4500));
List<ProductVO> list7 = productDAO.getAllProductListOrderByPriceDesc();
for(ProductVO vo:list7)
System.out.println(vo);
// 10. 상품 등록 시, 등록한 상품의 상품 번호 조회하기 (Oracle Sequence)
System.out.println("\n** 10. 상품 등록 시, 등록한 상품의 상품 번호 조회하기 **");
ProductVO paramVO2 = new ProductVO("바나나롤", "바나공장", 3500);
System.out.println("DB에 INSERT 전 정보: "+paramVO2);
productDAO.registerProductVer2(paramVO2);
System.out.println("DB에 INSERT 후 정보: "+paramVO2);
factory.close();
}
}
[ 결과 ]
'Java Web Programming > 6. Spring | MyBatis' 카테고리의 다른 글
[Spring/MyBatis] has a (aggregation) 관계 시, 구현방법 연습 (0) | 2020.11.03 |
---|---|
[Spring/MyBatis] JOIN 구문 연습 (inner join, outer join, group by) (0) | 2020.11.03 |
[MyBatis/Spring] 스프링에 마이바티스 적용해보기 (0) | 2020.10.30 |
[MyBatis] 마이바티스 적용 연습 2 ! (SELECT, INSERT, UPDATE + include & List, Map 타입 활용) (1) | 2020.10.30 |
[MyBatis] MyBatis 마이바티스 개념과 적용! (2) | 2020.10.29 |