23.1 마이바티스란?
- 애플리케이션 규모가 커지면서 JDBC로 개발하는데 한계(SQL문이 복잡, 연동 작업이 반복됨)가 생기며 마이바티스나 하이버네이트 같은 데이터 연동 관련 프레임워크가 등장
- 마이바티스를 사용하면 복잡한 SQL문도 SQL Developer 같은 도구에서 SQL문을 사용하는 것처럼 표준화된 방법으로 사용 가능
<마이바티스 프레임워크의 특징>
- SQL 실행 결과를 자바 빈즈나 Map 객체에 매핑해주는 Persistence 솔루션으로 관리
=> SQL을 소스코드가 아닌 XML로 분리
- SQL문과 프로그래밍 코드를 분리해서 구현
- datasource 기능과 트랜잭션 처리 기능을 제공
<마이바티스 프레임워크 동작 과정>
- 각 기능별로 실행할 SQL문을 xml파일(이하 SqlMap.xml이라 칭함)에 작성한 후 SqlMapConfig.xml에 등록
- 실행하고 싶은 sql문의 id와 데이터를 매개변수에 저장한 후 마이바티스에 전달
- 애플리케이션에서 요청한 SQL문을 SqlMap.xml에서 선택
- 전달한 매개변수와 선택한 SQL문을 DBMS에서 실행
- DBMS에서 반환된 데이터를 애플리케이션에서 제공하는 적당한 매개변수에 저장한 후 반환
23.2 마이바티스 설치하기
www.mybatis.org에 접속한 후 Products 탭 > MyBatis3 download > mybatis-x.x.x.zip 다운 > mybatis-x.x.x.jar 파일을 lib폴더에 넣기
+) ojdbc6.jar과 JSTL 라이브러리도 넣기
23.3 마이바티스 이용해 회원 기능 실습하기
* SqlMapConfig.xml : db 연동 시 반환되는 값을 저장할 빈이나 트랜잭션, 데이터소스 등 마이바티스 관련 정보를 설정
* member.xml : 회원 정보 관련 SQL문을 설정
>> 두 파일 모두 src 패키지 아래에 위치
- SqlMapConfig.xml
<?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>
<typeAliases>
<typeAlias type="com.spring.ex01.MemberVO" alias="memberVO"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="JDBC:oracle:thin:@localhost:1521:XE"/>
<property name="username" value="C##scott"/>
<property name="password" value="tiger"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mybatis/mappers/member.xml"/>
</mappers>
</configuration>
java
>> typeAlias : DAO에서 SQL문으로 값을 전달할 때 또는 SQL문을 실행한 결과 값을 DAO로 전달할 때 사용할 빈 생성
>> dataSource : 마이바티스 연동하는 db에 대한 데이터소스를 설정
>> mapper : 마이바티스에서 사용하는 SQL문이 있는 xml파일의 위치를 지정해서 읽어드림
- member.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">
<mapper namespace="mapper.member">
<resultMap id="memResult" type="memberVO">
<result property="id" column="id"/>
<result property="pwd" column="pwd"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
<result property="joinDate" column="joinDate"/>
</resultMap>
<select id="selectAllMemberList" resultMap="memResult">
<![CDATA[select * from t_member order by joinDate desc]]>
</select>
</mapper>
html
>> namespace : 다른 파일의 SQL문과 구분하기 위해 지정
>> resultMap : SQL문을 실행한 후 반환되는 레코드를 저장하기 위해 지정(typeAlias 태그에서 지정한 빈임)
>> type : 레코드의 컬럼 값을 속성에 저장하고 객체를 생성
>> select id : dao에서 SQL문을 구분하여 호출하기 위함
select resultMap : 위에서 지정한 resultMap의 id
>> SQL문의 < > <= >= 같은 연산자를 XML파일에서는 특수문자로 인식하여 오류 발생, 이러한 연산자들도 SQL문의 일부라는 것을 알려주기 위해 <![CDATA[...]> 태그 안에 SQL문을 작성
- MemberServlet.java
...
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MemberDAO dao=new MemberDAO();
List membersList=dao.selectAllMemberList();
request.setAttribute("membersList", membersList);
RequestDispatcher dispatch=request.getRequestDispatcher("test01/listMembers.jsp");
dispatch.forward(request, response);
}
java
- MemberDAO.java
public class MemberDAO {
private static SqlSessionFactory sqlMapper=null;
public static SqlSessionFactory getInstance() {
if(sqlMapper==null) {
try {
String resource="mybatis/SqlMapConfig.xml";
Reader reader=Resources.getResourceAsReader(resource);
sqlMapper=new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sqlMapper;
}
public List selectAllMemberList() {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
List<MemberVO> memList=null;
memList=session.selectList("mapper.member.selectAllMemberList");
return memList;
}
}
java
>> 각 메서드 호출 시 src/mybatis/SqlMapConfig.xml에서 설정 정보를 읽은 후 db와의 연동 준비
>> ~Builder : 마이바티스를 이용하는 sqlMapper 객체를 가져옴
>> openSession() : member.xml의 SQL문을 호출하는데 사용되는 SqlSession 객체를 가져 옴
>> selectList : 실행하고자 하는 SQL문의 id를 인자로 전달하여 여러 개의 레코드를 조회
23.4 마이바티스 이용해 회원 정보 CRUD 실습하기
<SqlSession 클래스에서 제공하는 여러 가지 메서드>
메소드 | 기능 |
List selectList(query_id, 조건) | id에 대한 select 문을 실행한 후 여러 레코드를 List로 반환 / 조건(파라미터)는 선택 |
T selectOne(query_id) | id에 대한 select 문을 실행한 후 지정된 타입으로 한 개의 레코드 반환 / 조건(파라미터)는 선택 |
Map<K,V> selectMap(query_id, 조건) | id에 대한 select문을 실행하면서 사용되는 조건도 전달. Map타입으로 레코드 반환 |
int insert(query_id, Object obj) | id에 대한 insert문을 실행하면서 객체 obj 값을 테이블에 추가 (sql문에서 #{}로 바로 obj의 속성 값 접근가능 |
int update(query_id, Object obj) | obj 객체의 값을 조건문의 수정 값으로 사용해 id데 대한 update문 실행 |
int delete(query_id, Object obj) | obj 객체의 값을 조건문의 조건 값으로 사용해 id데 대한 delete문 실행 |
<조건 값으로 회원 ID/pwd 조회 실습>
방법1) VO 이용
-servlet
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MemberDAO dao=new MemberDAO();
MemberVO memberVO=new MemberVO();
String name=dao.selectName();
int pwd=dao.selectPwd();
PrintWriter out=response.getWriter();
out.write("<script> alert('이름 : "+name+" 비밀번호: "+pwd+"'); </script>");
String nextPage="";
String action=request.getParameter("action");
if(action==null || action.contentEquals("listMembers")) {
List<MemberVO> membersList=dao.selectAllMemberList();
request.setAttribute("membersList", membersList);
nextPage="test01/listMembers.jsp";
}
else if(action.contentEquals("selectMemberById")) {
String id=request.getParameter("value");
memberVO=dao.selectMemberById(id);
request.setAttribute("mem", memberVO);
nextPage="test01/memberInfo.jsp";
}
else if(action.contentEquals("selectMemberByPwd")) {
String pwd2=request.getParameter("value");
List<MemberVO> membersList=dao.selectMemberByPwd(pwd2);
request.setAttribute("membersList", membersList);
nextPage="test01/listMembers.jsp";
}
RequestDispatcher dispatcher=request.getRequestDispatcher(nextPage);
dispatcher.forward(request, response);
}
java
- dao
...
public String selectName() {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
String name=session.selectOne("mapper.member.selectName");
return name;
}
public int selectPwd() {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
return session.selectOne("mapper.member.selectPwd");
}
public MemberVO selectMemberById(String id) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
return session.selectOne("mapper.member.selectMemberById",id);
}
public List selectMemberByPwd(String pwd) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
List<MemberVO> membersList=session.selectList("mapper.member.selectMemberByPwd",pwd);
return membersList;
}
java
>> selectOne / selectList의 두번째 인자를 넘겨주면 member.xml에서 ${id} 처럼 바로 조건 값으로 쓸 수 있음
- member.xml
<mapper namespace="mapper.member">
<resultMap id="memResult" type="memberVO">
<result property="id" column="id"/>
<result property="pwd" column="pwd"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
<result property="joinDate" column="joinDate"/>
</resultMap>
<select id="selectAllMemberList" resultMap="memResult">
<![CDATA[select * from t_member order by joinDate desc]]>
</select>
<select id="selectName" resultType="String">
<![CDATA[select name from t_member where id='hong']]>
</select>
<select id="selectPwd" resultType="int">
<![CDATA[select pwd from t_member where id='hong']]>
</select>
<select id="selectMemberById" resultType="memberVO" parameterType="String">
<![CDATA[select * from t_member where id=#{id}]]>
</select>
<select id="selectMemberByPwd" resultMap="memResult" parameterType="String">
<![CDATA[select * from t_member where pwd=#{pwd}]]>
</select>
</mapper>
html
>> parameterType : 조건값의 데이터 타입을 지정
>> 전달된 조건 값은 #{값}의 형식으로 사용
>> resultType="memberVO" : 조회되는 레코드를 반환하는데 그 개수가 한개인 경우
@@ pwd가 db에 string형으로 저장되어 있기 때문에 parameterType도 string이어야한다. int가 될 수 없다.
방법2) HashMap 이용
- servlet, dao
//servlet
..
MemberDAO dao=new MemberDAO();
List<HashMap<String,String>> membersList=dao.selectAllMemberList();
...
//dao
..
List<HashMap<String,String>> memList=null;
memList=session.selectList("mapper.member.selectAllMemberList");
..
java
- member.xml
...
<resultMap id="memResult" type="java.util.HashMap">
<result property="id" column="id"/>
<result property="pwd" column="pwd"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
<result property="joinDate" column="joinDate"/>
</resultMap>
...
html
>> resultMap의 type을 HashMap으로, resultMap의 VO가 필요없음
>> key-컬럼이름 , value-값
<회원 정보 추가>
>> member.xml에서 insert태그 사용
>> 조건으로 vo나 hashmap을 넘겨주면 속성/키를 #{}로 자유롭게 사용 가능
>> session.insert !
>> session.commit() 필요
방법1) VO 이용
- memberForm.jsp
<form method="post" action="${contextPath}/mem4.do?action=insertMember">
<h1 class="text_center">회원 가입창</h1>
<table align="center">
<tr>
<td width="200"><p align="right">아이디</td>
<td width="400"><input type="text" name="id"></td>
</tr>
...
html
- servlet
...
else if(action.contentEquals("insertMember")) {
String id=request.getParameter("id");
String pwd=request.getParameter("pwd");
String name=request.getParameter("name");
String email=request.getParameter("email");
memberVO=new MemberVO(id,pwd,name,email);
dao.insertMember(memberVO);
nextPage="/mem4.do?action=listMembers";
}
...
java
- dao
public int insertMember(MemberVO memberVO) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
int result=0;
result=session.insert("mapper.member.insertMember",memberVO);
session.commit();
return result;
}
java
- member.xml
<insert id="insertMember" parameterType="memberVO">
<![CDATA[insert into t_member(id,pwd,name,email) values(#{id},#{pwd},#{name},#{email})]]>
</insert>
html
방법2) HashMap 이용
- servlet / member.xml
//servlet
..
Map memberMap=new HashMap();
memberMap.put("id",id);
memberMap.put("pwd", pwd);
memberMap.put("name", name);
memberMap.put("email", email);
..
//member.xml
<insert id="insertMember2" parameterType="java.util.HashMap">
<![CDATA[insert into t_member(id,pwd,name,email) values(#{id},#{pwd},#{name},#{email})]]>
</insert>
java
<회원 정보 수정 실습>
>> 추가와 member.xml만 다르고 나머진 거의 같음~ (여기선 회원가입과 동일하게 작성)
- dao
result=session.update("mapper.member.updateMember",memberVO);
session.commit();
java
-member.xml
<update id="updateMember" parameterType="MemberVO">
<![CDATA[update t_member set pwd=#{pwd}, name=#{name}, email=#{email} where id=#{id}]]>
</update>
html
<회원 정보 삭제 실습>
>> 이 역시 member.xml만 다름
- list.jsp
..
<td><b>삭제</b></td>
</tr>
<c:forEach var="mem" items="${membersList }">
<td><a href="${contextPath}/mem4.do?action=deleteMember&id=${member.id }">삭제하기</a></td>
..
html
- dao
result =session.delete("mapper.member.deleteMember",id);
session.commit();
java
- member.xml
<delete id="deleteMember" parameterType="String">
<![CDATA[delete from t_member where id=#{id}]]>
</delete>
html
23.5 마이바티스의 동적 SQL문 사용하기
- (기존 SQL문) 각각의 조건절에 따라 각각의 SQL문을 작성해야 함
- 마이바티스의 동적 SQL문 : if. foreach 등을 이용해 한개의 SQL문으로 각 조건절들을 구현
- 동적 SQL문은 주로 where절을 동적으로 추가
- 동적 SQL문에 사용되는 태그들은 JSP의 JSTL에서 사용되는 코어(c) 태그들과 유사
- <![CDATA.. 안에 쓰지 않아도 됨
<동적 SQL문을 구성하는 요소들>
- if
- choose(when, otherwise)
- trim(where, set)
- foreach
<if> 태그로 동적 SQL문 만들기
- <where> 태그 안에서 사용(where 조건 절에서 where 표시)
- <where> 태그 : <if> 태그에 따라 조건식이 존재하면 공통 SQL문에 where절을 추가
- <where> <if test="조건식"> 추가할 구문 </if> </where>
- members.xml
<select id="searchMember" parameterType="MemberVO" resultMap="memResult">
<![CDATA[select * from t_member]]>
<where>
<if test="name!='' and name!=null">
name=#{name}
</if>
<if test="email!='' and email!=null">
and email=#{email}
</if>
</where>
order by joinDate desc
</select>
html
>>test 조건식에서 name, email은 memberVO의 속성이다.
>> 조건절에 속성 사이에 and를 써야 함에 주의!!
- servlet
else if(action.contentEquals("searchMember")) {
String name=request.getParameter("name");
String email=request.getParameter("email");
memberVO.setName(name);
memberVO.setEmail(email);
List<MemberVO> members=dao.selectMember(memberVO);
request.setAttribute("membersList", members);
nextPage="test03/listMembers.jsp";
}
java
- dao
public List<MemberVO> selectMember(MemberVO memberVO) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
List<MemberVO> list=session.selectList("mapper.member.searchMember", memberVO);
return list;
}
java
<choose> 태그로 동적 SQL문 만들기
- members.xml
<select id="searchMember" parameterType="MemberVO" resultMap="memResult">
<![CDATA[select * from t_member]]>
<where>
<choose>
<when test="name!='' and name!=null and email!='' and email!=null>
name=#{name} and email=#{email}
</when>
<when test="name!='' and name!=null">
name=#{name}
</when>
<when test="email!='' and email!=null">
and email=#{email}
</when>
<when>
</where>
order by joinDate desc
</select>
html
>> switch문과 같은 기능으로, 위에서부터 맞는 조건이 있으면 빠져 나옴
>> <choose> <when test=조건식> ~ </when> <choose>
>> otherwise문도 당연히 쓸 수 있음
<foreach> 태그로 회원 정보 조회하기
<foreach item="item" collection="list" index="index" open=" (" close=")" separator=","> #{item} </foreach>
- collection : 전달받은 인자 값의 데이터 타입, 유형은 list나 array 둘 중 하나. => parameterType은 java.util.Map이다.
- index : 몇번 째 반복인지를 담은 변수, 최초는 0
- open / close : 구문이 시작/끝날 때 지정한 기호 추가
- separator : 반복되는 사이에 추가되는 기호
~ where name in (a.b,c) 를 만들어보자
- member.xml
<select id="foreachSelect" parameterType="java.util.Map" resultMap="memResult">
<![CDATA[select * from t_member]]>
where name in
<foreach item="item" collection="list" open=" (" close=")" separator=",">
#{item}
</foreach>
order by joinDate desc
</select>
html
>> parametrType의 요소를 item으로 지칭
- servlet
else if(action.contentEquals("foreachSelect")){
List<String> nameList=new ArrayList();
nameList.add("차범근");
nameList.add("이순신");
nameList.add("홍길동");
List<MemberVO> membersList=dao.foreachSelect(nameList);
request.setAttribute("membersList", membersList);
nextPage="test03/listMembers.jsp";
}
java
- dao
public List<MemberVO> foreachSelect(List<String> nameList) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
return session.selectList("mapper.member.foreachSelect",nameList);
}
java
<foreach> 태그로 bulkInsert
- 오라클에서는 insert문을 동시에 여러 개 사용하면 오류 발생(MySQL은 ㄱㅊ)
- 해결방법!!>> <foreach> 태그의 open과 close 속성에 SQL문을 설정한 후 서브 쿼리 형식으로 다중 insert문 구현
- INSERT ALL INTO t_member VALUES()'(반복) SELECT * FROM DUAL
- member.xml
<insert id="foreachInsert" parameterType="java.util.Map">
<foreach item="item" collection="list" open="INSERT ALL" close="SELECT * FROM DUAL" separator=" ">
INTO t_member(id,pwd,name,email)
VALUES (#{item.id}, #{item.pwd}, #{item.name}, #{item.email})
</foreach>
</insert>
html
- servlet
else if(action.contentEquals("foreachInsert")) {
List<MemberVO> memList=new ArrayList();
memList.add(new MemberVO("m1","1234","박길동","m1@test.com"));
memList.add(new MemberVO("m2","1234","이길동","m2@test.com"));
memList.add(new MemberVO("m3","1234","유길동","m3@test.com"));
int result=dao.foreachInsert(memList);
nextPage="/mem4.do?action=listMembers";
}
java
- dao
public int foreachInsert(List<MemberVO> memList) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
int result=session.insert("mapper.member.foreachInsert",memList);
session.commit();
return result;
}
java
<sql> 태그와 <include> 태그로 SQL문 중복 제거하기
- <sql> 태그로 공통으로 들어가는 sql문을 지정할 수 있다. id 속성으로 이름을 지정
- <include> 태그의 refid 속성에 위에서 지정한 sql문 이름을 넣어 공통 SQL문을 끼워 넣음
- member.xml
<sql id='a'>
<![CDATA[select * from t_member ]]>
</sql>
<select id="searchMember" parameterType="MemberVO" resultMap="memResult">
<include refid='a'/>
<where>
...
html
* 마이바티스에서 오라클 연동해 like 검색하는 방법
where name like '%'|| #{속성} || '%'
처럼 '%' 기호와 조건 값 사이에는 || 기호를 넣어 연결
예시) select * from t_member where name like '%' || #{name} || '%'
- member.xml
<select id="selectLike" parameterType="String" resultMap="memResult">
<include refid="a"/>
<![CDATA[where name like '%' || #{name} || '%']]>
</select>
html
- servlet
else if(action.contentEquals("selectLike")) {
String name="길";
List<MemberVO> membersList=dao.selectLike(name);
request.setAttribute("membersList", membersList);
nextPage="test03/listMembers.jsp";
}
java
- dao
public List<MemberVO> selectLike(String name) {
sqlMapper=getInstance();
SqlSession session=sqlMapper.openSession();
return session.selectList("mapper.member.selectLike",name);
}
java
'BackEnd > Spring' 카테고리의 다른 글
22장. 스프링 JDBC 기능 (0) | 2022.03.02 |
---|---|
21장. 스프링 MVC 기능 (0) | 2022.03.01 |
20장. 스프링 AOP 기능 (0) | 2022.02.28 |
19장. 스프링 의존성 주입과 제어 역전 기능 (0) | 2022.02.27 |
18장. 스프링 프레임워크 시작하기 (0) | 2022.02.26 |
Comment