본문 바로가기
Programming/JDBC

MyBatis(2) MyBatis 사용

by yoon9i 2024. 4. 4.


MyBatis 프레임워크

1. 개요
- JDBC 사용을 편리하고 효율적으로 기능이 추가된 형태의 SQL Mapping Framework 프레임워크.
- ibatis ( OLD 버전; mybatis 이전 버전 )

2. 홈페이지 가서 필요한 jar 다운로드 하자.
http://mybatis.org

1) mybatis-3.5.14
2) assets -> mybatis-3.5.14.zip 다운

3) 압축풀기
mybatis-3.5.14.jar ( build path 대상임 )
mybatis-3.5.14.pdf ( 매뉴얼, https://mybatis.org/mtbatis-3/ )

3. 이클립스에서 build path

1) 프로젝트 생성
2) 2개의 jar 파일 build path
- mysql-connector-j-8.jar (mysql 드라이버)
- mybatis-3.5.14.jar

- 자바프로젝트 선택 > 오른쪽 클릭 > build path > Configure build path > Libraries > 
   ClassPath > ADD External jar... > mysql-connector-j-8.3.0.jar 선택( .jar 파일로 선택해야함. )

4. MyBatis 사용방법
1) JDBC 에서 사용햇던 4가지 정보를 외부파일에 저장.
=> jdbc.properties
=> src 폴더에 저장. ( 패키지 설정 가능 )

* properties 파일
key=value
key=value

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.userid=root
jdbc.passwd=1234

2) 최소 2개의 xml 파일이 필요
=> *.xml
=> src 폴더에 저장. ( 패키지 설정 가능 )

가. 설정파일
- 용도 : mybtis 사용시 환경설정 정보들 관리 ( DB 연동정보, DTO별칭, mapper 등록 )
- Configuration.xml

나. mapper 파일
- 용도: JDBC 에서 사용했던 SQL 문을 저장하는 파일.
- 테이블당 하나씩 작성. ( 테이블명Mapper.xml )
- DeptMapper.xml
  EmpMapper.xml

https://mybatis.org/mybatis-3/getting-started.html 에서 Configuration 과 Mapper xml 복사하였음.


* Configuration.xml 파일을 읽는 자바 코드가 필요.
==> com.config.MySqlSessionFactory.java 만들고 하단코드를 복사해서 사용.

``
String resource = "com/config/Configuration.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
  new SqlSessionFactoryBuilder().build(inputStream);
``

* JDBC vs MyBatis

가. JDBC 에서 필요한 API
- Connection
- PrepareStatement
- ResultSet

나. MyBatis 에서 필요한 API
- SqlSesstionFactory
- SqlSession ( * )
==> SqlSession session = MySqlSessionFactory.getSession( );


* SqlSession 의 메서드
==> DeptMapper.xml 에 있는 태그를 호출하는 메서드

가. select 작업

# 단일 레코드 반환
DeptDTO dto = session.selectOne( " namespace명.mapper 의 id값 " );
DeptDTO dto = session.selectOne( " namespace명.mapper 의 id값 ", Onject obj ); // obj 는 WHERE 절에 사용

# 다중 레코드 반환
List<DeptDTO> list = session.selectList( " namespace명.mapper 의 id값 " );
List<DeptDTO> list = session.selectList( " namespace명.mapper 의 id값 ", Object obj ); // obj 는 WHERE 절에 사용

나. insert 작업

int n = session.insert( " namespace명.mapper 의 id값 " );
int n = session.insert( " namespace명.mapper 의 id값 ", Object obj ); // obj 는 저장할 데이터

다. update 작업

int n = session.update( " namespace명.mapper 의 id값 " );
int n = session.update( " namespace명.mapper 의 id값 ", Object obj ); // obj 는 수정할 데이터

라. delete 작업

int n = session.delete( " namespace명.mapper 의 id값 " );
int n = session.delete( " namespace명.mapper 의 id값 ", Object obj ); // obj 는 삭제할 데이터


3) 하나의 레코드를 저장하는 DTO 작성 ( * )
==> select 된 결과인 레코드를 DTO 에 저장한다.
        단, 연결고리가 존재한다. 
        테이블의 컬럼명(컬럼헤더값)과 DTO 의 변수명이 일치해야 된다.

ex)

CREATE TABLE dept
( deptno INT PRIMARY KEY,
 dname  VARCHAR(20),
 loc       VARCHAR(20) );

SELECT deptno AS no, dname, loc FROM dept; -- int deptno 에 저장안됨.

public class DeptDTO {

  int deptno;
  String dname;
               String loc;

}

* parameterType="전달할 파라미터의 타입" 종류
https://mybatis.org/mybatis-3/configuration.html#typealiases

* 자동으로 select 한 결과가 DTO 저장이 되고 반대로 파라미터로 전달한 
  DTO 의 변수값이 #{ 변수값 } ( getXXX 이용 )  로 치환이 됨.
- 가능한이유? 테이블의 컬럼명과 DTO 의 변수명이 일치하기 때문이다.
      정확한 문법은 컬럼명과 DTO 의 getXXX( ) 와 setXXX( ) 가 되어야 한다.


* id 값이 일치하지 않는 경우의 에러
Mapped Statements collection does not contain value for findByDnameOrLoc3 .... 
이런오류가 난다면 id 값이 잘못적힌것이니 최대한 id 는 복사붙여넣기 할것.


4) com.dto.DeptDTO 의 별칭 지정하기
==> com.dto.DeptDTO 를 DeptDTO(별칭) 로 지정
==> Configuration.xml 에서 별칭 지정하고 Mapper 에서 별칭을 사용한다.

문법:

<typeAliases>
   <typeAlias alias="DeptDTO" type="com.dto.DeptDTO"/>
</typeAliases>


##########################################################

5. MyBatis 동적sql( Dynamic SQL ) 처리 ( emp 테이블로 실습 )

1) 다중 insert 처리

mysql sql 문:

INSERT INTO emp ( empno, ename, sal )
VALUES ( 10,  'a', 100 ), ( 20,  'a', 100 ), ( ), ....; -- 동적으로 처리

mybatis sql 문:
        <insert id="multiInsert" parameterType="arraylist">
INSERT INTO emp ( empno, ename, sal )
VALUES
<foreach item="dto"  collection=" list ", separator=" , ">
      (  #{ dto.empno }, #{ dto.ename }, #{ dto.sal }     )
</foreach> <!-- list 갯수만큼 반복해서 ( ) 를 만듬 -->
        </insert> 
``

 

<공통> ----------------------------------------------------------------------------------------------------------------------------------------------------

# com.config 를 생성후 jdbc.properties 를 text 형식으로 만들어서 하단의 텍스트 추가
# 단, 한글로 쓰면 깨지게 되니 마우스 우클릭후 properties 에서 UTF-8 설정 

# 주석문
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.userid=root
jdbc.passwd=1234

 

properties 설정하는 이미지 ↓

package com.config;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MySqlSessionFactory {

	static SqlSessionFactory sqlSessionFactory;
	static {
		String resource = "com/config/Configuration.xml";
		InputStream inputStream = null;
		try {
			inputStream = Resources.getResourceAsStream(resource);
		} catch (IOException e) {
			e.printStackTrace();
		}
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	}// end static 블럭

	// SqlSessionFactory 로부터 SqlSession 얻는 메서드
	public static SqlSession getSession() {
		// MyBatis는 명시적으로 commit 지정해야 된다.
		SqlSession session = sqlSessionFactory.openSession(); // openSession(false) 동일
		return session;
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

	<!-- jdbc.properties 등록 -->
	<properties resource="com/config/jdbc.properties"></properties>
	
	<!-- DTO 별칭 -->
	<typeAliases>
		<typeAlias type="com.dto.DeptDTO" alias="DeptDTO"/>
		<typeAlias type="com.dto.EmpDTO" alias="EmpDTO"/>
	</typeAliases>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<!-- jdbc.properties 등록된 값을 참조: ${key} -->
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.userid}" />
				<property name="password" value="${jdbc.passwd}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- DeptMapper.xml 등록 -->
		<mapper resource="com/config/DeptMapper.xml" />
		<mapper resource="com/config/DeptMapper2.xml" />
		
		<mapper resource="com/config/EmpMapper.xml"/>
	</mappers>
</configuration>

 

<DeptDTO>

package com.dto;

// 역할: dept 테이블의 컬럼(레코드)을 저장하는 역할.
// 규칙: select 할 때 반환되는 컬럼의 헤더값으로 변수를 지정해야 된다.
public class DeptDTO {
	
	int deptno;
	String dname;
	String loc;
	
	public DeptDTO() {
		// TODO Auto-generated constructor stub
	}

	public DeptDTO(int deptno, String dname, String loc) {
		this.deptno = deptno;
		this.dname = dname;
		this.loc = loc;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	public String getDname() {
		return dname;
	}

	public void setDname(String dname) {
		this.dname = dname;
	}

	public String getLoc() {
		return loc;
	}

	public void setLoc(String loc) {
		this.loc = loc;
	}

	@Override
	public String toString() {
		return "DeptDTO [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
	}	
	
}

 

<EmpDTO>

package com.dto;

public class EmpDTO {
	
	int empno;
	String ename;
	String job;
	int mgr;
	String hiredate; // 날자는 연산이 필요없으면 그냥 String 으로 처리
	int sal;
	int comm;
	int deptno;
	
	public EmpDTO() {
		// TODO Auto-generated constructor stub
	}

	public EmpDTO(int empno, String ename, String job, int mgr, String hiredate, int sal, int comm, int deptno) {
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.mgr = mgr;
		this.hiredate = hiredate;
		this.sal = sal;
		this.comm = comm;
		this.deptno = deptno;
	}

	public int getEmpno() {
		return empno;
	}

	public void setEmpno(int empno) {
		this.empno = empno;
	}

	public String getEname() {
		return ename;
	}

	public void setEname(String ename) {
		this.ename = ename;
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public int getMgr() {
		return mgr;
	}

	public void setMgr(int mgr) {
		this.mgr = mgr;
	}

	public String getHiredate() {
		return hiredate;
	}

	public void setHiredate(String hiredate) {
		this.hiredate = hiredate;
	}

	public int getSal() {
		return sal;
	}

	public void setSal(int sal) {
		this.sal = sal;
	}

	public int getComm() {
		return comm;
	}

	public void setComm(int comm) {
		this.comm = comm;
	}

	public int getDeptno() {
		return deptno;
	}

	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}

	@Override
	public String toString() {
		return "EmpDTO [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hiredate="
				+ hiredate + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + "]";
	}
	
	
	
	
}

 

---------------------------------------------------------------------------------------------------------------------------------------------------------

 

<기본사용>

import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.config.MySqlSessionFactory;
import com.dto.DeptDTO;

public class MyBatisDeptMain {

	public static void main(String[] args) {

	   //1. SqlSession 얻기
		SqlSession session =
				MySqlSessionFactory.getSession();
		
		//2. SqlSession의 메서드를 이용해서 DeptMapper.xml과 연동
		List<DeptDTO> list = session.selectList("findAll");
		
		System.out.println("################################");
		DeptDTO xxx  = session.selectOne("findByDeptno", 10);
		
		
		System.out.println("################################");
		
		DeptDTO yyy = new DeptDTO();
		yyy.setDname("인사과");
		yyy.setLoc("BOSTON");
		List<DeptDTO> list2 = session.selectList("findByDnameOrLoc", yyy);
		System.out.println("################################");
		
		HashMap<String, String> map = new HashMap<>();
		map.put("x", "인사과");
		map.put("y", "BOSTON");
		List<DeptDTO> list3 = session.selectList("findByDnameOrLoc2", map);
		//3. 출력
		System.out.println(list3);
		
		//4. close작업
		session.close();
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.config.DeptMapper">

	<!-- 전체 조회 -->
	<select id="findAll" resultType="DeptDTO">
		SELECT deptno, dname, loc
		FROM dept
		ORDER BY deptno DESC
	</select>

	<!-- 조건 조회1 -->
	<!-- mapper 에서는 #{} / resultType: 결과값의 타입 / parameterType: 전달되는값의 타입(#{} 이 있으면 꼭 사용해야함.) -->
	<select id="findByDeptno" resultType="DeptDTO" parameterType="int">
		SELECT deptno, dname, loc
		FROM dept
		WHERE deptno = #{deptno}		
	</select>
	
	
	<!-- 조건 조회2 -->
	<select id="findByDnameOrLoc" resultType="DeptDTO" parameterType="DeptDTO">
		SELECT deptno, dname, loc
		FROM dept
		WHERE dname = #{dname} OR loc = #{loc}
	</select>

	<!-- 조건 조회3 -->
	<select id="findByDnameOrLoc2" resultType="DeptDTO" parameterType="hashmap">
		SELECT deptno, dname, loc
		FROM dept
		WHERE dname = #{x} OR loc = #{y}
	</select>

</mapper>

 

 

<응용>

id 를 적어주면 되지만 명확하게는 위치까지 같이 적어주는게 좋다.

import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.config.MySqlSessionFactory;
import com.dto.DeptDTO;

// default package
public class MyBatisDeptMain1_select기초 {

	public static void main(String[] args) {
		
		// 1. SqlSession 얻기
		SqlSession session = 
				MySqlSessionFactory.getSession();
		
		// 2. SqlSession 의 메서드를 이용해서 DeptMapper.xml 과 연동
		List<DeptDTO> list = session.selectList("com.config.DeptMapper.findAll"); // -> DeptMapper 의 select id="findAll" 연동
		
		// --------------------------------------------------
		DeptDTO xxx = session.selectOne("com.config.DeptMapper.findByDeptno", 10);
		
		// --------------------------------------------------
		DeptDTO yyy = new DeptDTO();
		yyy.setDname("인사과");
		yyy.setLoc("BOSTON");
		List<DeptDTO> list2 = session.selectList("com.config.DeptMapper.findByDnameOrLoc",yyy);
		 
		// --------------------------------------------------
		HashMap<String, String> map = new HashMap<>();
		map.put("x", "인사과");
		map.put("y", "BOSTON");
		List<DeptDTO> list3 = session.selectList("com.config.DeptMapper.findByDnameOrLoc2",map);				
		// ---------------------------------------------------
		
		// 3. 출력
		System.out.println("--------------------------------");
		System.out.println(list);
		System.out.println("--------------------------------");
		System.out.println(xxx);
		System.out.println("--------------------------------");
		System.out.println(list2);
		System.out.println("--------------------------------");
		System.out.println(list3); 
		
		// 4. close 작업
		session.close();
		
	}// end main

}// end class
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.config.DeptMapper">

	<!-- 전체 조회 -->
	<select id="findAll" resultType="DeptDTO">
		SELECT deptno, dname, loc
		FROM dept
		ORDER BY deptno DESC
	</select>

	<!-- 조건 조회1 -->
	<!-- mapper 에서는 #{} / resultType: 결과값의 타입 / parameterType: 전달되는값의 타입(#{} 이 있으면 꼭 사용해야함.) -->
	<select id="findByDeptno" resultType="DeptDTO" parameterType="int">
		SELECT deptno, dname, loc
		FROM dept
		WHERE deptno = #{deptno}		
	</select>
	
	
	<!-- 조건 조회2 -->
	<select id="findByDnameOrLoc" resultType="DeptDTO" parameterType="DeptDTO">
		SELECT deptno, dname, loc
		FROM dept
		WHERE dname = #{dname} OR loc = #{loc}
	</select>

	<!-- 조건 조회3 -->
	<select id="findByDnameOrLoc2" resultType="DeptDTO" parameterType="hashmap">
		SELECT deptno, dname, loc
		FROM dept
		WHERE dname = #{x} OR loc = #{y}
	</select>

</mapper>

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

<DML>

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.config.MySqlSessionFactory;
import com.dto.DeptDTO;

// default package
public class MyBatisDeptMain2_DML {

	public static void main(String[] args) {
		
		// 1. SqlSession 얻기
		SqlSession session = MySqlSessionFactory.getSession();
//		List<DeptDTO> listDeptMapper = session.selectList("com.config.DeptMapper.findAll");
		List<DeptDTO> list = session.selectList("com.config.DeptMapper2.findAll");
		
//		System.out.println(listDeptMapper);
		System.out.println(list);
		
		// 데이터 저장 1 -------------------------------------------------
//		DeptDTO dto = new DeptDTO(1, "개발", "부산");
//		int n = session.insert("com.config.DeptMapper2.save", dto);
//		session.commit();
//		System.out.println(n + " 개가 생성됨.");
		

		// 데이터 수정 -------------------------------------------------
		DeptDTO dto2 = new DeptDTO(1, "IT개발", "부산시");
		int n2 = session.update("com.config.DeptMapper2.update", dto2);
		session.commit();
		System.out.println(n2 + " 개가 업데이트됨.");
		
		// 데이터 삭제 -------------------------------------------------
		int deptno = 1;
		int n3 = session.delete("com.config.DeptMapper2.remove",deptno);
		session.commit();
		System.out.println(n3 + " 개가 삭제됨.");
		
		// 4. close 작업 -------------------------------------------------
		session.close();
		
	}// end main

}// end class
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.config.DeptMapper2">

	<!-- 전체 조회 -->
	<select id="findAll" resultType="DeptDTO">
		SELECT deptno, dname, loc
		FROM dept
		ORDER BY deptno ASC
	</select>

	<!-- 저장 -->
	<select id="save" parameterType="DeptDTO">
		INSERT INTO dept ( deptno, dname, loc )
		VALUES ( #{deptno}, #{dname}, #{loc} )
	</select>

	<!--
	<select id="save2" parameterType="DeptDTO">
		INSERT INTO dept ( deptno, dname )
		VALUES ( #{}, #{dname} )
	</select>
	만약 값이 없다면 전체적으로 오류가 발생함으로 잘 확인할것.
	-->

	<!-- 수정 -->
	<update id="update" parameterType="DeptDTO">
		UPDATE dept
		SET dname = #{dname}, loc = #{loc}
		WHERE deptno = #{deptno}
	</update>

	<!-- 삭제 -->
	<delete id="remove" parameterType="int">
		DELETE FROM dept
		WHERE deptno = #{deptno}
	</delete>

	<delete id="removeByDname" parameterType="String">
		DELETE FROM dept
		WHERE dname = #{dname}
	</delete>

</mapper>

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------

 

<emp 테이블 이용해서 mybatis 동적처리>

import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.config.MySqlSessionFactory;
import com.dto.EmpDTO;

public class MyBatisEmpMain {

	public static void main(String[] args) {
		
		// 한꺼번에 저장
		EmpDTO dto1 = new EmpDTO(1, "aaa1", "SALESMAN", 7369, null, 700, 0, 30);
		EmpDTO dto2 = new EmpDTO(2, "aaa2", "SALESMAN", 7369, null, 700, 0, 30);
		EmpDTO dto3 = new EmpDTO(3, "aaa3", "SALESMAN", 7369, null, 700, 0, 30);
		
		List<EmpDTO> list = Arrays.asList(dto1, dto2, dto3);
		
		SqlSession session = MySqlSessionFactory.getSession();
		
		//
		int n = session.insert("com.config.EmpMapper.multiInsert", list);
		session.commit();
		System.out.println(n + " 개가 저장됨.");
		//
		
		session.close();

	}

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.config.EmpMapper">

	<!-- 
	INSERT INTO emp ( empno, ename, sal )
	VALUES ( 10,  'a', 100 ), ( 20,  'a', 100 ), ( ), ....;	
	-->	
	<insert id="multiInsert" parameterType="arraylist">
		INSERT INTO emp ( empno, ename, job, mgr, hiredate, sal, comm, deptno )
		VALUES
		<foreach item="dto" collection="list" separator=",">
			( #{dto.empno}, #{dto.ename}, #{dto.job} , #{dto.mgr} ,now(), #{dto.sal}, #{dto.comm}, #{dto.deptno} )
		</foreach>
	</insert>

	
</mapper>

 

 

'Programming > JDBC' 카테고리의 다른 글

MyBatis(4) 아키텍쳐  (0) 2024.04.05
MyBatis(3) 동적sql 처리  (0) 2024.04.05
MyBatis(1) 설치 및 설정  (0) 2024.04.04
JDBC(2) 트랜잭션  (0) 2024.04.04
JDBC(1) 기본 + 응용 + 예외처리  (1) 2024.04.03