SQL : Structured Query Language
Database 에 명령하는 언어이다.
JDBC : Java DataBase Connectivity
SQL 을 Java 코드 내에서 작성할 수 있도록 하는 Java 와 DB 를 연동해 주는 기술이다.
다음은 간단한 상품 등록 insert 코드이다.
package com.model2.mvc.service.product.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import com.model2.mvc.common.Search;
import com.model2.mvc.common.util.DBUtil;
import com.model2.mvc.service.domain.Product;
public class ProductDAO {
//Constructor
public ProductDAO() {
}
//Method
public void insertProduct(Product product) throws Exception {
Connection con = DBUtil.getConnection();
String sql = "INSERT INTO product VALUES (seq_product_prod_no.nextval, ?, ?, ?, ?, ?, sysdate) ";
PreparedStatement pstmt = con.prepareStatement(sql);
//prod_no = seq_product_prod_no.nextval (다음 번호 시퀀스 진행)
pstmt.setString(1, product.getProdName()); //prod_name
pstmt.setString(2, product.getProdDetail()); //prod_detail
pstmt.setString(3, product.getManuDate()); //manufacture_day
pstmt.setInt(4, product.getPrice()); // price
pstmt.setString(5, product.getFileName()); // image_file
// regDate 는 sysdate
pstmt.executeUpdate();
pstmt.close();
con.close();
} //end of insertProduct
} // end of class
DB 연결, SQL 작성, Object 에서 불러온 값 쿼리에 setting, sql execute DB statement, connection 닫기로 마무리 까지 순수 메서드만 약 20 줄 가량이다.
DAO(Data Access Object) 에서 반복되는 jdbc, SQL 을 xml(meta-data) 기반으로 옮겨와, 코드 유지 관리를 보다 수월하게 해주고, 상황에 맞게 동적 SQL 도 구사할 수 있게 해주는 framework
MyBatis 는 xml 에 meta-data 를 기재해서 설정, Column-Object mapping 등을 한다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis-config.xml :: MyBatis Framework MetaData -->
<configuration>
<!-- FQCN(Full Qualified Class Name) Alias(별칭관리) -->
<typeAliases>
<typeAlias alias="user" type="com.model2.mvc.service.domain.User" />
<typeAlias alias="product" type="com.model2.mvc.service.domain.Product" />
<typeAlias alias="purchase" type="com.model2.mvc.service.domain.Purchase" />
<typeAlias alias="search" type="com.model2.mvc.common.Search" />
</typeAliases>
<!-- SQL Definition :: file include -->
<mappers>
<mapper resource="sql/UserMapper.xml"/>
<mapper resource="sql/ProductMapper.xml"/>
<mapper resource="sql/PurchaseMapper.xml"/>
</mappers>
</configuration>
해당 파일 내에 FQCN 을 alias 로 관리하고 mapper 파일 url 을 지정했다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ProductMapper">
<!-- 각 column 과 Product bean 의 field 를 연결 -->
<resultMap id="productSelectMap" type="product">
<result property="prodNo" column="prod_no" jdbcType="NUMERIC"/>
<result property="prodName" column="prod_name" jdbcType="VARCHAR" />
<result property="prodDetail" column="prod_detail" jdbcType="VARCHAR" />
<result property="manuDate" column="manufacture_day" jdbcType="VARCHAR" />
<result property="price" column="price" jdbcType="INTEGER" />
<result property="fileName" column="image_file" jdbcType="VARCHAR" />
<result property="regDate" column="reg_date" jdbcType="DATE" />
<result property="rowNum" column="row_seq" jdbcType="NUMERIC"/>
</resultMap>
<!-- SQL : SELECT LIST -->
<select id="getProductList" parameterType="search" resultMap="productSelectMap">
SELECT *
FROM ( SELECT inner_table.* , ROWNUM AS row_seq
FROM ( SELECT p.prod_no, p.prod_name, p.price, p.reg_date, t.tran_status_code
FROM product p
LEFT OUTER JOIN transaction t
ON p.prod_no = t.prod_no
<if test="searchCondition != null">
<where>
<if test="searchCondition == 0 and searchKeyword !='' ">
p.prod_no = #{searchKeyword}
</if>
<if test="searchCondition == 1 and searchKeyword !='' ">
p.prod_name = #{searchKeyword}
</if>
<if test="searchCondition == 2 and searchKeyword !='' ">
p.price = #{searchKeyword}
</if>
</where>
</if>
ORDER BY prod_no ) inner_table
WHERE ROWNUM <= #{endRowNum} )
WHERE row_seq BETWEEN #{startRowNum} AND #{endRowNum}
</select>
<!-- 위 두번째 subQuery 의
WHERE ROWNUM <= #{endRowNum} ) 는 less than
WHERE ROWNUM <= #{endRowNum} ) 의미이며..
< 는 keyword 로 < 를 사용.
<![CDATA[ ~~~ ]]> 를 이용하여 아래와 같이 사용 할 수 있다.
CDATA ==> Character Data 의 의미 Java 에서 \n 같은 특수문자 처리
WHERE ROWNUM <![CDATA[ <=]]> #{endRowNum} )
-->
<!-- SQL : SELECT ROW Count -->
</mapper>
위 xml 에 서술한 SQL 과 같이 searchCondition 이 null 이 아닐 경우,
searchCondition 에 세팅한 value 에 따라 동적으로 query 가 날아가도록 만들어줄 수 있다.
그리고 Business logic 과 Persistence 계층을 더 제대로 나누어 코드 유지 관리가 쉽도록 했다.
package com.model2.mvc.service.product.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import com.model2.mvc.common.Search;
import com.model2.mvc.service.domain.Product;
import com.model2.mvc.service.product.ProductDao;
//==> 제품관리 DAO CRUD 구현 중 List 예시
@Repository("productDaoImpl")
public class ProductDaoImpl implements ProductDao {
///Field
@Autowired
@Qualifier("sqlSessionTemplate")
private SqlSession sqlSession;
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
//Constructor
public ProductDaoImpl() {
System.out.println(this.getClass());
}
@Override
public List<Product> getProductList(Search search) throws Exception {
return sqlSession.selectList("ProductMapper.getProductList", search);
}
}
다음은 기존
Struts framework
(.do, Action) 기반에서Spring framework(+MVC Pattern)
로 전환 내역을 기록 예정이다.