JDBC
MyBatis Framework
데이터베이스를 따로 관리
JPA - ORM 방식
자바 안에서 데이터베이스를 관리. (테이블생성, 제약조건 모두)
- 1인칭, 2인칭, 3인칭 관점
- 프로그램을 완성을 한 뒤 (A,B,C,D,E,F) 배치까지 끝난 상태에서 Z라는 기능을 추가하고싶다면 (재배치) 중간중간 원하는 곳에 넣을 수 있다.
- Z라는 기능이 A 입장에선 after, B입장에선 before
잘 활용하진 않는다.
지금까지 sql을 연결 할 땐 모두 string으로 불러온다.
실시간으로 에러를 확인할 수 없다.
MyBatis에서는 이 부분을 외부로 들어낸다.
여기서 sql문이 틀리면 프로그램이 오류를 잡아준다.
그렇게 되면 데이터베이스를 더 쉽게 접근하고 관리할 수 있다.
대신 .xml문서에 작성해야한다. (여는태그, 닫는태그에 코드를 작성한다)
따로 설정을 해줘야한다.
xml문서를 객체화 시켜주는 annotation이 있다.
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:mapper_xml_files
- 이렇게 작성해준다.
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:mybatis_dynamic_sql
..
<select id="selectEmployerList" parameterType="egovframework.rte.psl.dataaccess.vo.EmpVO" resultType="egovframework.rte.psl.dataaccess.vo.EmpVO">
<![CDATA[
select
EMP_NO as empNo,
EMP_NAME as empName,
JOB as job,
MGR as mgr,
HIRE_DATE as hireDate,
SAL as sal,
COMM as comm,
DEPT_NO as deptNo
from EMP
]]>
<where>
<if test="empNo != null">
EMP_NO = #{empNo}
</if>
<if test="empName != null">
EMP_NAME LIKE '%' || #{empName} || '%'
</if>
</where>
</select>
두 가지 값을 모두 제공하지 않는다면 HIRE 상태인 Employee 정보가 리턴될 것이다.
<select id="selectEmployeeList" parameterType="egovframework.rte.psl.dataaccess.vo.EmpVO" resultType="egovframework.rte.psl.dataaccess.vo.EmpVO">
SELECT * FROM EMP WHERE JOB = ‘Engineer’
<choose>
<when test=”mgr ! null”>
AND MGR like #{mgr}
</when>
<when test=”empNo ! null and empName ! =null”>
AND EMP_NAME like #{empName}
</when>
<otherwise>
AND HIRE_STATUS = ‘Y’
</otherwise>
</choose>
</select>
..
<select id="selectEmployerList" parameterType="egovframework.rte.psl.dataaccess.vo.EmpVO"
resultType="egovframework.rte.psl.dataaccess.vo.EmpVO">
<![CDATA[
select
EMP_NO as empNo,
EMP_NAME as empName,
JOB as job,
MGR as mgr,
HIRE_DATE as hireDate,
SAL as sal,
COMM as comm,
DEPT_NO as deptNo
from EMP
]]>
<trim prefix="WHERE" prefixOverrides="AND|OR ">
<if test="empNo != null">
EMP_NO = #{empNo}
</if>
<if test="empName != null">
EMP_NAME LIKE '%' || #{empName} || '%'
</if>
</trim>
</select>
<select id="selectJobHistListUsingDynamicNestedIterate" parameterType="egovframework.rte.psl.dataaccess.util.EgovMap" resultMap="jobHistVO">
<![CDATA[
select EMP_NO as empNo,
START_DATE as startDate,
END_DATE as endDate,
JOB as job,
SAL as sal,
COMM as comm,
DEPT_NO as deptNo
from JOBHIST
]]>
where
<foreach collection="condition" item="item" open="(" separator="and" close=")">
${item.columnName} ${item.columnOperation}
<if test="item.nested == 'true'">
<foreach item="item" index="index" collection="item.columnValue" open="(" separator="," close=")">
'${item}'
</foreach>
</if>
<if test="item.nested != 'true'">
#{item.columnValue}
</if>
</foreach>
order by EMP_NO, START_DATE
</select>
http://blog.mybatis.org/
https://mybatis.org/mybatis-3/ko/java-api.html
factory라는 단어가 많이 나오는데, 어떤 걸 만들어줄테니 사용하라는 의미이다. (공장)
이걸 @Bean이 한번에 처리해준다.
의존성 주입.
이와 관련하여 보통 factory라는 이름이 많이 나온다.
※ 주의사항 : 맥OS 에서는 oraclepki.jar, osdf_cert.jar, osdf_core.jar 추가해야 함
- 배포할 땐 이 구조가 나와야한다.
- classes는 backend단
- views는 front단
DBOpen클래스 + DAO클래스 를 한번에 ㅎㅎ
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:configuration_xml
getting_started
복붙 긁어오기
<?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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
driver, url, username, password을 오라클 아이디 비밀번호로 변경한다.
※ 비밀번호를 변경하면 ?
xml만 배포해주면 된다.
원하는 곳에 annotation만 선언해서 사용하면 된다.
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:getting_started
<?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="egovframework.rte.psl.dataaccess.DeptMapper">
<select id="selectDept"
parameterType="int"
resultType="Dept">
<![CDATA[
select *
from DEPT
where DEPT_NO = #{deptNo}
]]>
</select>
</mapper>
MemDTO.java
MemMainTest.java
클래스 생성
클래스에 대한 별칭 부여
매개변수로 MemDTO를 사용하도록 설정하는 것이다.
이제 비밀번호를 변경하면 이 부분만 바꿔주면 된다.
1) DB연결 환경 설정 파일 가져오기
2) DB연결하기 위한 팩토리빈(factory bean) 생성
- 이전에 배웠던 DBOpen + DAO와 같은 기능이다.
run 실행방법 - Java Application
이렇게 의존성을 주입시켜주는 것이다.
DB연결 시 비밀번호 등 변경을 하려면 (유지보수) jdbc.xml의 내용만 변경해주면 된다.
3) 쿼리문 생성 및 변환
4) 쿼리문 실행
↓ DTO에 생성자 추가 후 다시 작성
4) 다시 와서 쿼리문 작성
※ type을 다르게 줘도 실행이 된다 하지만 밑에있는 걸 추천
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:mapper_xml_files
==> DTO 설정이 굉장히 중요하다.
DTO가 없었으면 그냥 #{n} 으로 작성해도 되는데
매개변수가 DTO이기 때문에 반드시 DTO에서 설정한 변수이름을 사용해줘야 한다
※ 연산자 작성 시 유의사항
xml 페이지에서는 열고닫는 태그를 이용해서 구성을 하는데, 연산자를 넣게되면 태그인지, 연산자인지 구분을 해줘야한다.
이걸 사용해주면 꺽쇠기호를 연산자로 처리해준다.
MyBatis3 동적 SQL (Oracle, MySQL)
[MyBatis-3 Dynamic SQL]
※ Dynamic SQL
- 일반적으로 JDBC API를 사용한 코딩에서 다양한 조건에 따라 다양한 형태의 쿼리의 실행이 필요한 경우가 존재하며
이에 MyBatis는 강력한 동적 SQL 언어를 제공한다.
- MyBatis에서 제공하는 동적 SQL 요소들은 JSTL 이나 XML 기반의 텍스트 프로세서와 유사한 형태로 제공되며
OGNL 기반의 표현식을 제공함으로써 보다 유연하고 편리하게 Dynamic 요소를 사용할 수 있다.
- 전자정부 표준 프레임워크 참조
http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte2:psl:dataaccess:mybatis_dynamic_sql
1. 일반적인 SQL 사용
<?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 = "member">
<select id='checkId' resultType='int' parameterType='String'>
SELECT COUNT(id) as cnt
FROM member
WHERE id=#{id}
</select>
<insert id="create" parameterType="MemberVO">
INSERT INTO member(mno, id, passwd, mname, tel, zipcode, address1, address2, mdate)
VALUES ((SELECT NVL(MAX(mno), 0)+1 as mno FROM member),
#{id}, #{passwd}, #{mname}, #{tel}, #{zipcode}, #{address1}, #{address2}, sysdate)
</insert>
<!-- 검색을하지 않는 전체 목록 -->
<select id="list" resultType="MemberVO">
SELECT mno, id, passwd, mname, tel, zipcode, address1, address2, mdate
FROM member
ORDER BY mno ASC
</select>
<!-- 조회 -->
<select id="read" resultType="MemberVO" parameterType="int">
SELECT mno, id, passwd, mname, tel, zipcode, address1, address2, mdate
FROM member
WHERE mno = #{mno}
</select>
<update id="update" parameterType="MemberVO">
UPDATE member
SET mname=#{mname}, tel=#{tel}, zipcode=#{zipcode},
address1=#{address1}, address2=#{address2}
WHERE mno=#{mno}
</update>
<select id="passwdCheck" resultType="int" parameterType="Map">
SELECT COUNT(mno) as cnt
FROM member
WHERE mno=#{mno} AND passwd=#{passwd}
</select>
<update id="update_passwd" parameterType="Map">
UPDATE member
SET passwd=#{passwd}
WHERE mno=#{mno}
</update>
<delete id="delete" parameterType="int">
DELETE FROM member
WHERE mno=#{mno}
</delete>
<select id="login" resultType="int" parameterType="MemberVO">
SELECT COUNT(mno) as cnt
FROM member
WHERE id=#{id} AND passwd=#{passwd}
</select>
</mapper>
2. 동적인 SQL 사용 (Oracle)
1) WHERE를 분리한 경우
<select id="list3" resultType="BlogVO" parameterType="HashMap">
SELECT blogno, blogcategoryno, title, content, good, file1, file2, size2, cnt, replycnt, rdate
FROM blog
WHERE blogcategoryno=#{blogcategoryno}
<choose>
<when test="col == 'title'">
AND title LIKE '%' || #{word} || '%'
</when>
<when test="col == 'content'">
AND content LIKE '%' || #{word} || '%'
</when>
<when test="col == 'title_content'">
AND title LIKE '%' || #{word} || '%' OR content LIKE '%' || #{word} || '%'
</when>
</choose>
ORDER BY blogno DESC
</select>
<select id="count" resultType="int" parameterType="HashMap">
SELECT COUNT(*) as cnt
FROM blog
WHERE blogcategoryno=#{blogcategoryno}
<choose>
<when test="col == 'title'">
AND title LIKE '%' || #{word} || '%'
</when>
<when test="col == 'content'">
AND content LIKE '%' || #{word} || '%'
</when>
<when test="col == 'title_content'">
AND title LIKE '%' || #{word} || '%' OR content LIKE '%' || #{word} || '%'
</when>
</choose>
</select>
<!-- ********** 검색, 페이징 시작 ********** -->
<select id="list" resultType="BlogVO" parameterType="HashMap" >
SELECT blogno, title, good, thumb, file1, size1, cnt, rdate, r
FROM(
SELECT blogno, title, good, thumb, file1, size1, cnt, rdate, rownum as r
FROM(
SELECT blogno, title, good, thumb, file1, size1, cnt, rdate
FROM blog
<choose>
<when test="col == 'title'">
WHERE title LIKE '%' || #{word} || '%'
</when>
<when test="col == 'content'">
WHERE content LIKE '%' || #{word} || '%'
</when>
<when test="col == 'title_content'">
WHERE title LIKE '%' || #{word} || '%' OR content LIKE '%' || #{word} || '%'
</when>
</choose>
ORDER BY blogno DESC
)
)
WHERE <![CDATA[r >=#{startNum} AND r <= #{endNum}]]>
</select>
<!-- ********** 검색, 페이징 종료 ********** -->
2) WHERE를 명시한 경우
<select id="list3" resultType="BlogVO" parameterType="HashMap">
SELECT blogno, blogcategoryno, title, content, good, file1, file2, size2, cnt, replycnt, rdate
FROM blog
WHERE blogcategoryno=#{blogcategoryno}
<where>
<choose>
<when test="col == 'title'">
AND title LIKE '%' || #{word} || '%'
</when>
<when test="col == 'content'">
AND content LIKE '%' || #{word} || '%'
</when>
<when test="col == 'title_content'">
AND title LIKE '%' || #{word} || '%' OR content LIKE '%' || #{word} || '%'
</when>
</choose>
<where>
ORDER BY blogno DESC
</select>
<select id="count" resultType="int" parameterType="HashMap">
SELECT COUNT(*) as cnt
FROM blog
WHERE blogcategoryno=#{blogcategoryno}
<where>
<choose>
<when test="col == 'title'">
AND title LIKE '%' || #{word} || '%'
</when>
<when test="col == 'content'">
AND content LIKE '%' || #{word} || '%'
</when>
<when test="col == 'title_content'">
AND title LIKE '%' || #{word} || '%' OR content LIKE '%' || #{word} || '%'
</when>
</choose>
</where>
</select>
3. 동적인 SQL 사용 (MySQL)
------------------------------------------------- notice.xml
<?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">
<!-- namespace는 인터페이스가 와야함.
interface NoticeMapper{} -->
<mapper namespace="kr.co.mango.notice.NoticeMapper">
<select id="getArticleList" resultType="NoticeDTO" parameterType="hashmap" >
SELECT noticeno, nobigclass, nosubclass, subject, content, regDate,hits
FROM notice
WHERE noticeno > 0
<!-- 공지사항(1)/ FAQ(2) -->
<choose>
<when test="nobigclass != '' ">
AND nobigclass = #{nobigclass}
</when>
</choose>
<!-- 검색조건 -->
<choose>
<when test="word != '' and col.equals('subject')">
AND subject like CONCAT('%',#{word},'%')
</when>
<when test="word != '' and col.equals('content')">
AND content like CONCAT('%',#{word},'%')
</when>
<when test="word != '' and col.equals('subject_content')">
AND subject like CONCAT('%',#{word},'%') OR content like CONCAT('%',#{word},'%')
</when>
</choose>
ORDER BY noticeno DESC
LIMIT <![CDATA[#{start}, #{end}]]>
</select>
<select id="getCount" resultType="java.lang.Integer" parameterType="hashmap" >
SELECT COUNT(*)
FROM notice
WHERE noticeno > 0
<if test="col == 'subject' and word!=''">
AND subject like CONCAT('%',#{word},'%')
</if>
<if test="col == 'content' and word!=''">
AND content like CONCAT('%',#{word},'%')
</if>
<if test="col == 'subject_content' and word!=''">
AND subject like CONCAT('%',#{word},'%') OR content like CONCAT('%',#{word},'%')
</if>
</select>
<insert id="create" parameterType="NoticeDTO">
INSERT INTO notice (nobigclass, nosubclass, subject, content, regDate, modDate)
VALUES (#{nobigclass}, #{nosubclass}, #{subject}, #{content}, now(), now())
</insert>
<select id="read" parameterType="int" resultType="NoticeDTO">
SELECT noticeno, nobigclass, nosubclass, subject, content, regDate
FROM notice
WHERE noticeno = #{noticeno}
</select>
<update id="update" parameterType="NoticeDTO">
UPDATE notice SET
nobigclass = #{nobigclass},
nosubclass = #{nosubclass},
subject = #{subject},
content = #{content},
modDate = now()
WHERE noticeno = #{noticeno}
</update>
<delete id="delete" parameterType="int">
DELETE FROM notice
WHERE noticeno = #{noticeno}
</delete>
</mapper>
group과 Artifact 는 저렇게 생성해줘야한다. (이전 것 틀림)
springbean.xml 에서
kr.co.itwill.di.MessageKO2
kr.co.itwill.di.MessageEN2
로
내용을 바꾸어도
다른 페이지는 수정할 곳이 없다.
다른 페이지와의 의존성을 줄이는 것이다.