Coffe Bean package를 온라인 웹 사이트로 주문합니다. 매일 전날 오후 2시부터 오늘 오후 2시까지의 주문을 모아서 처리합니다.
Spring Boot, Mybatis, MySQL Mybatis 사용 방식을 익히기 위한 프로젝트이므로, Mybatis 사용에 목적을 두었습니다. 로그인 기능 X
자바에서는 데이터의 영속성을 위한 JDBC를 지원해주는데, 매핑 작업을 개발자가 일일히 수행해야 하고, 쿼리문이 번거로워진다. SQL Mapper와 ORM은 개발자가 직접 JDBC Programming을 하지 않도록 기능을 제공하는 Persistence Framework 이다.
객체와 SQL 필드를 매핑하여 데이터를 객체화 하는 기술으로, SQL을 직접 작성하고, 쿼리 수행 결과를 어떤 객체에 매핑할지 바인딩한다. 선택한 DBMS의 문법으로 쿼리문을 직접 작성해야 하므로, DBMS에 종속적인 특징이 있다.
자바에서 SQL Mapper를 지원해주는 프레임 워크로, 쿼리문을 xml 파일로 분리할 수 있고, 동적 쿼리도 작성할 수 있다.
장점
단점
SqlSessionFactoryBuilder
가 설정파일을 참고하여 SqlSessionFactory
생성SqlSessionFactory
는 매 요청마다 SqlSession
객체를 생성mapper
인터페이스 객체를 가져옴mapper
가 SqlSession
호출하여 xml 파일에 있는 SQL을 실행
SqlSession
: MyBatis의 컴포넌트로, SQL을 실행하고 트랜잭션 제어하는 역할
SqlSessionFactory
: SqlSession을 생성하기 위한 컴포넌트
SqlSessionFactoryBuilder
: 마이바티스 설정 파일을 읽어들여 SqlSessionFactory
를 생성하기 위한 컴포넌트
SqlSessionFactoryBean
: SqlSessionFactory를 구축하고, 스프링 DI에 객체를 저장하기 위한 컴포넌트
MapperScannerConfigurer
: 지정한 패키지 아래 모든 인터페이스가 MapperInterface로 간주되어 Mapper 인터페이스 객체가 빈으로 등록된다.
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
파라미터는 위와 같이 #{}안에 파라미터명을 넣어 표기한다.
<select
id="selectPerson"
parameterType="int"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
select문에는 위와 같은 많은 속성들을 활용할 수 있다. 보통은 post시 parameterType, get시 resultType, resultMap을 많이 사용한다.
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
insert문에는 위와 같이 속성 사용 가능한데, keyProperty와 keyColumn, useGeneratedKeys를 활용하여 insert한 데이터의 key를 반환받을 수 있다.
update, delete문은 별다른 특별한 속성은 없다.
반환하고 싶은 형식을 지정하고 싶다면, resultMap을 사용할 수 있다.
<resultMap id="orderResultMap" type="org.cafe.gccoffee.model.dto.order.response.OrderResponse">
<id property="id" column="id"/>
<result property="email" column="email"/>
<result property="address" column="address"/>
<result property="postcode" column="postcode"/>
<result property="orderStatus" column="orderStatus"/>
<result property="createdAt" column="createdAt"/>
<result property="updatedAt" column="updatedAt"/>
<collection property="orderItems" ofType="org.cafe.gccoffee.model.dto.order.response.OrderItemResponse">
<result property="productName" column="productName"/>
<result property="quantity" column="quantity"/>
<result property="totalPrice" column="totalPrice"/>
</collection>
</resultMap>
<select id="getOrderList" resultMap="orderResultMap">
SELECT BIN_TO_UUID(O.ORDER_ID) as id,
O.EMAIL,
O.ADDRESS,
O.POSTCODE,
O.ORDER_STATUS as orderStatus,
P.PRODUCT_NAME as productName,
OI.QUANTITY,
OI.PRICE as totalPrice,
O.CREATED_AT as createdAt,
O.UPDATED_AT as updatedAt
FROM ORDERS O
INNER JOIN ORDER_ITEMS OI ON BIN_TO_UUID(O.ORDER_ID) = BIN_TO_UUID(OI.ORDER_ID)
INNER JOIN PRODUCTS P ON BIN_TO_UUID(OI.PRODUCT_ID) = BIN_TO_UUID(P.PRODUCT_ID)
ORDER BY O.CREATED_AT DESC
LIMIT #{size}
OFFSET #{offset}
</select>
이 프로젝트의 코드에서 가져오자면, 이렇게 resultmap을 생성해서 매핑해주고, select속성의 resultMap에 생성한 resultMap의 id를 넣어주면 된다. property는 내가 resultMap의 type으로 지정한 OrderResponse dto의 필드명이고, column은 sql의 결과로 반환된 컬럼의 이름이다. collection을 사용하면 중첩된 결과도 collection으로 반환받을 수 있다.
<select id="getProductList" resultType="org.cafe.gccoffee.model.dto.product.ProductResponse">
SELECT BIN_TO_UUID(PRODUCT_ID) as id,
PRODUCT_NAME as productName,
CATEGORY,
PRICE,
DESCRIPTION,
CREATED_AT
FROM PRODUCTS
WHERE
<if test="category != null">
category = #{category}
</if>
ORDER BY CREATED_AT ASC
LIMIT #{size}
OFFSET #{offset}
</select>