[JAVA]_MYBATIS, JDBC

전희주·2023년 4월 23일
0

JAVA

목록 보기
14/24

MYBATIS

MYBATIS 구조 및 개념

  • https://wjun.tistory.com/47

  • 객체지향 언어인 자바의 관계형 데이터 베이스 프로그래밍(jdbc)을 사용하기 쉽게 도와주는 프레임워크다

  • DB framework는 jdbc 단점을 해결하기 위해 사용한다

  • Mybatis를 사용하는 이유도 jdbc의 단점을 해결해주기 때문이다

  • JDBC의 단점으로

    • 1) JDBC는 1개의 클래스에 반복된 코드가 존재한다
    • 2) 자바언어와 sql언어 2가지가 하나의 클래스에 있기 때문에 재사용성이 좋지 않다
  • 기존 DAO클래스에서 DB실행을 위해 작성한 JDBC 코드를 XML로 분산한다

    • xml의 이름만 호출하면 DB연결을 할 수 있다
    • DAO클래스 내 코드를 작성할 필요가 없어진다
  • MYBATIS 실행 구조

MYBATIS 실습 코드 분석

  • 실행 순서
    jdbc.properties → Configuration.xml → DeptDTO → DeptMapper.xml → DeptDAO → DeptService → DeptServiceImpl → DeptMain

  • jdbc.properties: DB 접속 정보가 저장되어 있는 파일로, DB 연결을 위해 필요한 정보를 제공합니다.

  • Configuration.xml: MyBatis 설정 파일입니다. MyBatis 설정 파일은 MyBatis 프레임워크를 사용하는 데 필요한 정보를 제공하며, DB 연결 정보와 매퍼 파일 경로 등을 설정합니다.

  • DeptDTO: 부서 정보를 저장하는 DTO(Data Transfer Object) 클래스입니다. 테이블 컬럼명과 동일한 변수명을 사용하여 DB와 연결됩니다.

  • DeptMapper.xml: SQL 쿼리를 작성하는 매퍼 파일입니다. MyBatis의 쿼리 실행기가 실행할 SQL을 작성하는데 사용됩니다.

  • DeptDAO: 부서 정보를 DB에 조회, 추가, 수정, 삭제하는 기능을 담당하는 DAO(Data Access Object) 인터페이스입니다. MyBatis의 쿼리 실행기와 연동되며, 매퍼 파일에서 작성한 SQL을 실행합니다.

  • DeptServiceImpl: 부서 정보 관련 비즈니스 로직을 처리하는 서비스 클래스입니다. DAO 인터페이스를 사용하여 DB 작업을 수행합니다.

  • DeptMain: 부서 정보 관리 프로그램의 실행 클래스입니다. 서비스 객체를 생성하고, 사용자 입력에 따라 해당 기능을 수행하는 메뉴를 보여줍니다.

jdbc.properties

# comment
#key=value
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.userid=SCOTT
jdbc.passwd=TIGER

Configuration.xml

<?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/mybatis/jdbc.properties"></properties>
   
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <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>
    <mapper resource="com/mybatis/DeptMapper.xml"/>
   </mappers>
</configuration>

  • 위 코드는 MyBatis의 설정 파일인 configuration.xml입니다.
    • <properties>: JDBC 드라이버 정보를 담은 jdbc.properties 파일을 등록합니다.
    • <environments>: MyBatis가 동작하는 환경 정보를 등록합니다. default 속성으로 development를 지정하였습니다.
    • <transactionManager>: MyBatis에서 사용할 트랜잭션 매니저의 타입을 지정합니다. 이 경우, JDBC를 사용하겠다고 지정합니다.
    • <dataSource>: 데이터베이스 접속 정보를 등록합니다. type 속성으로 POOLED를 지정하였으며, 이는 데이터베이스 커넥션을 풀링하는 방식으로 접속을 관리하겠다는 것을 의미합니다.
    • <property>: 드라이버, URL, 계정, 비밀번호 등 데이터베이스 접속 정보를 등록합니다. 이 정보들은 ${}를 사용하여 jdbc.properties에서 불러옵니다.
    • <mappers>: MyBatis가 사용할 SQL 문장이 작성된 매퍼 파일의 위치를 지정합니다. 이 경우 com.mybatis.DeptMapper.xml을 사용하겠다고 지정합니다.

DeptDTO

package com.dto;


public class DeptDTO {
	 // 관례적으로 dept테이블의 컬럼명을 변수명으로 지정한다
		int deptno;
		String dname;
		String loc;
		
		public DeptDTO() {}
		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 + "]";
		}
}
  • 부서(Dept) 정보를 담는 DTO(Data Transfer Object) 클래스입니다.

    • 이 클래스는 DAO와 Service 클래스에서 부서 정보를 전달할 때 사용됩니다.
  • 클래스 내부에는 deptno, dname, loc 3개의 멤버변수가 선언되어 있습니다. 각 멤버변수는 int, String 타입으로 선언되어 있습니다.

  • 생성자는 매개변수로 deptno, dname, loc 3개의 값을 받습니다.

  • Getter와 Setter 메서드는 멤버변수에 대한 Getter와 Setter 메서드로, 값을 가져오거나 저장할 때 사용됩니다.

  • toString() 메서드는 객체의 정보를 문자열로 출력하는 메서드로, 해당 객체의 deptno, dname, loc 값을 문자열로 출력합니다.

DeptMapper.xml

  • namespace 란?
    • namespace 속성을 사용하여 해당 XML 파일의 이름공간을 명시함으로써, 같은 이름공간(namespace) 내에서 유일한 ID 값을 가진 각 SQL 문을 식별할 수 있게 됩니다.
    • 따라서 같은 이름공간(namespace) 내에서 중복된 ID를 가진 SQL문은 에러가 발생하며, namespace 속성 값이 다르면 다른 이름공간으로 구분되어 서로 다른 SQL문으로 인식됩니다.
    • 간단히 말해, namespace를 사용함으로써 여러 개의 Mapper 파일에서 SQL문을 구분할 수 있습니다.
  • 이 파일은 com.mybatis.DeptMapper라는 namespace를 가지고 있습니다.
<select id="selectDynamicDeptno" 
 	        parameterType="hashmap" 
 	        resultType="com.dto.DeptDTO">
 	   select deptno, dname, loc from dept
 	   <if test="x != null">
 	     where deptno = #{x}
 	   </if>
 	</select>
  • : Dept 테이블에서 deptno가 주어진 값인 레코드를 검색하는 쿼리입니다. 파라미터로 HashMap 타입이 사용되며, 결과로는 DeptDTO 객체가 반환됩니다.

  • <if test="x != null">: 동적 SQL을 사용하여 조건문을 추가하는 태그입니다. test 속성에서 지정한 조건이 참일 경우 해당 태그 내부의 SQL 문이 추가됩니다.

 <select id="selectDynamicChoose"
            parameterType="hashmap" 
 	        resultType="com.dto.DeptDTO">
 	   select deptno, dname, loc from dept
 	   <choose>
 	     <when test="loc != null">
 	       where loc = #{loc}
 	     </when>
 	     <when test="dname != null">
 	       where dname = #{dname}
 	     </when>
 	     <when test="dname != null and loc !=null">
 	       where dname = #{dname} and loc = #{loc}
 	     </when>
 	     <otherwise>
 	       order by deptno desc
 	     </otherwise>
 	   </choose>    
   </select>
  • : Dept 테이블에서 주어진 조건에 따라 레코드를 검색하는 쿼리입니다. choose와 when을 사용하여 여러 조건을 확인한 후 적절한 쿼리를 수행합니다.
  • <choose>: 여러 개의 조건 중 하나를 선택하여 실행하는 동적 SQL을 구현할 때 사용하는 태그입니다.
  • <when test="loc != null">: choose 태그 내부에서 각 조건을 지정하는 태그입니다. when 태그는 test 속성에서 지정한 조건이 참일 경우 해당 태그 내부의 SQL 문이 실행됩니다.
  • <otherwise>: choose 태그 내부에서 마지막 조건을 지정하는 태그입니다. when 태그 중 어떤 것도 참이 아닐 경우 해당 태그 내부의 SQL 문이 실행됩니다.
 <update id="updateDynamic" 
           parameterType="com.dto.DeptDTO">
      update dept
      <trim prefix="SET" suffixOverrides=",">
         <if test="loc != null">
          loc = #{loc},
         </if>
         <if test=" dname != null">
          dname = #{dname}
         </if>
	  </trim>
      where deptno=#{deptno}
   </update>
  • : Dept 테이블에서 주어진 deptno에 해당하는 레코드를 업데이트하는 쿼리입니다. trim, if 등을 사용하여 동적으로 SQL 쿼리를 생성합니다.

  • <trim prefix="SET" suffixOverrides=",">: SET 키워드를 포함하는 문장을 작성하는 데 사용되는 태그입니다.

    • prefix는 해당 문자열이 포함될 위치를 지정하며, suffixOverrides는 해당 문자열 뒤에 제거될 문자열을 지정합니다.
  <select id="multiSelect" parameterType="arraylist"
                        resultType="com.dto.DeptDTO">
     select * from dept
     where deptno IN
      <foreach item="item" index="index" collection="list"
        open="(" separator="," close=")" >
          #{item.deptno}
    </foreach>
   </select>
  • : Dept 테이블에서 주어진 deptno 리스트에 해당하는 레코드를 검색하는 쿼리입니다. foreach를 사용하여 동적인 IN 절을 생성합니다.

  • <foreach item="item" index="index" collection="list" open="(" separator="," close=")" >: foreach 루프를 사용하여 컬렉션의 요소를 반복하면서 SQL 문을 동적으로 생성하는 태그입니다.

    • item은 반복될 컬렉션의 요소를 담을 변수명을, index는 인덱스를, collection은 반복될 컬렉션의 이름을, open은 시작 문자열을, separator는 구분 문자열을, close는 끝 문자열을 지정합니다.

DeptDAO

  • "com.mybatis.DeptMapper.selectDynamicChoose"는 "com.mybatis" 패키지 내에 위치한 DeptMapper.xml 파일에서 "selectDynamicChoose"라는 id를 가진 SQL 문을 나타냅니다.
    • 이 SQL 문은 HashMap 객체를 매개 변수로 받아 조건에 따라 동적으로 WHERE 절을 구성하여 해당하는 부서 정보를 조회하는 기능을 수행합니다.
    • 동적 SQL은 쿼리문의 일부 또는 전체를 조건부로 생성할 수 있는 방법입니다. where 절은 검색 조건에 따라 조건이 추가될 수 있기 때문에 where 절에서 동적 SQL을 사용하는 것이 일반적입니다.
    1. DeptDAO 클래스 선언부
package com.dao;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.dto.DeptDTO;


//1. DeptDAO 클래스 선언부 
// DeptDAO 클래스 선언부이다. 
public class DeptDAO {
	
    1. selectDynamicDeptno() 메서드
	// 2. selectDynamicDeptno() 메서드
	public List<DeptDTO> 
	selectDynamicDeptno(SqlSession session, HashMap<String, Integer> map){
		List<DeptDTO> list =
				session.selectList("com.mybatis.DeptMapper.selectDynamicDeptno", map);
		return list;
	}
	
    1. selectDynamicChoose() 메서드
    		/*
    		 *  SqlSession 객체를 생성하는 것은 DeptServiceImpl에서 한번만 하면 되기 때문에, 
    		 *  DeptDAO에서는 생성하지 않고 전달받아 사용
    		 *  
    		 *  DeptDAO 클래스에서는 SqlSession 객체를 생성하지 않고, 
    		 *  인자로 전달받은 SqlSession 객체를 활용하여 
    		 *  SQL을 실행
    		 *  
    		 *  selectDynamicDeptno() 메서드는 SqlSession 객체와 HashMap 객체를 매개변수로 받는다.
    		 *  SqlSession 객체를 사용하여 mybatis에서 매핑된 select 쿼리문을 실행하여 
    		 *  결과를 List 형태로 반환한다.
    		 *
    		 * */ 
    	
    		// 3. selectDynamicChoose() 메서드
    		public List<DeptDTO> 
    		selectDynamicChoose(SqlSession session, HashMap<String, String> map){
    			List<DeptDTO> list =
    		session.selectList("com.mybatis.DeptMapper.selectDynamicChoose", map);
    			return list;
    		}
    	
    		/*
    		 * 위 코드에서 "com.mybatis.DeptMapper.selectDynamicChoose"는 "com.mybatis" 패키지 내에 위치한 DeptMapper.xml 파일에서 "selectDynamicChoose"라는 id를 가진 SQL 문을 나타냅니다. 이 SQL 문은 HashMap 객체를 매개 변수로 받아 조건에 따라 동적으로 WHERE 절을 구성하여 해당하는 부서 정보를 조회하는 기능을 수행합니다.
    		 * 동적 SQL은 쿼리문의 일부 또는 전체를 조건부로 생성할 수 있는 방법입니다. where 절은 검색 조건에 따라 조건이 추가될 수 있기 때문에 where 절에서 동적 SQL을 사용하는 것이 일반적입니다.
    		 * 
    		 * selectDynamicChoose() 메서드는 SqlSession 객체와 HashMap 객체를 매개변수로 받는다. 
    		 * SqlSession 객체를 사용하여 
    		 * mybatis에서 매핑된 select 쿼리문을 실행하여 
    		 * 결과를 List 형태로 반환한다.
    		 * */
    	
  
- 4. updateDynamic() 메서드
  
```java 
	// 4. updateDynamic() 메서드
	public int updateDynamic(SqlSession session, DeptDTO dto) {
		int n = session.update("com.mybatis.DeptMapper.updateDynamic", dto);
		return n;
	}
	
	/*
	 * 
	 *   updateDynamic() 메서드는 SqlSession 객체와 DeptDTO 객체를 매개변수로 받는다.
	 *   SqlSession 객체를 사용하여 mybatis에서 매핑된 update 쿼리문을 실행하고, 
	 *   영향받은 행의 개수를 반환한다.
	 *   
	 *   
	 * */
    1. multiSelect() 메서드
	public List<DeptDTO> 
	multiSelect(SqlSession session, List<DeptDTO> xxx){
		List<DeptDTO> list =
				session.selectList("com.mybatis.DeptMapper.multiSelect", xxx);
		return list;
	}
	
	
	/*
	 * 
	 *  multiSelect() 메서드는 SqlSession 객체와 DeptDTO 리스트를 매개변수로 받는다.
	 *  SqlSession 객체를 사용하여 mybatis에서 매핑된 select 쿼리문을 실행하여 결과를 List 형태로 반환한다. 
	 *  이 때, 
	 *  매개변수로 전달된 DeptDTO 리스트는 쿼리문에서 사용되는 파라미터이다.
	 * 
	 * 
	 * */
}

DeptService

  • Mybatis를 이용하여 부서(Dept) 테이블과 관련된 다양한 서비스를 제공하는 인터페이스인 DeptService를 선언하는 코드입니다.

  • 동적 SQL은 실행 시점에 파라미터 값을 받아 쿼리를 동적으로 생성하는 것

package com.service;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.dto.DeptDTO;

public interface DeptService {
  
	public List<DeptDTO> selectDynamicDeptno(HashMap<String, Integer> map);
  
	public List<DeptDTO> 
	selectDynamicChoose(HashMap<String, String> map);
  
	public int updateDynamic(DeptDTO dto); 
  
	public List<DeptDTO> multiSelect(List<DeptDTO> xxx);
  
}
  • selectDynamicDeptno: 동적으로 SQL을 생성하여 부서번호(deptno)에 따라 부서 정보를 검색하는 메서드입니다. 매개변수로 HashMap 객체를 받아 사용합니다.
  • selectDynamicChoose: 동적으로 SQL을 생성하여 부서 이름(dname) 또는 지역(loc)에 따라 부서 정보를 검색하는 메서드입니다. 매개변수로 HashMap 객체를 받아 사용합니다.
  • updateDynamic: 동적으로 SQL을 생성하여 부서 정보를 수정하는 메서드입니다. 매개변수로 DeptDTO 객체를 받아 사용합니다.
  • multiSelect: 여러 개의 부서번호(deptno)에 대해 동적으로 SQL을 생성하여 부서 정보를 검색하는 메서드입니다. 매개변수로 List 객체를 받아 사용합니다.
  • 이 인터페이스를 구현하는 클래스에서는 SqlSession 객체를 이용하여 Mybatis를 활용한 SQL 실행 및 결과 처리가 이루어집니다.

DeptServiceImpl

  • DeptServiceImpl 클래스는 MyBatis를 이용한 데이터베이스 서비스를 제공하기 위한 메서드들을 구현하고, DeptDAO 클래스의 메서드들을 호출하여 실제 DB 연동 작업을 처리합니다.
    1. static 블록: sqlSessionFactory 객체 생성
    • static 블록은 클래스 로딩 시점에 실행되며,
    • DeptServiceImpl 클래스 내부에 static으로 선언된 sqlSessionFactory 객체를 생성합니다.
    • sqlSessionFactory는 MyBatis를 사용하기 위한 필수 객체(팩토리 클래스)이며, MyBatis를 사용하기 위해서는 SqlSessionFactory를 먼저 생성해야 합니다.
      • SqlSessionFactory를 생성하기 위해 SqlSessionFactoryBuilder 클래스의 build() 메소드를 호출하고, 이때 Configuration.xml 파일을 로드
    • Configuration.xml 파일을 읽어 SqlSessionFactory 객체를 생성합니다.

    • Configuration.xml 파일은 MyBatis 설정 파일로, 데이터베이스 연결 정보와 매퍼 파일 위치 등의 설정이 포함되어 있습니다.
      • 따라서 Configuration.xml 파일이 로드되어 inputStream 변수에 할당되면 SqlSessionFactoryBuilder 클래스의 build() 메소드를 호출하여 sqlSessionFactory 객체를 생성합니다.
      • 이렇게 생성된 sqlSessionFactory는 static 변수로 선언되어 있으므로, DeptServiceImpl 클래스 내에서 공유해서 사용할 수 있습니다.
      • Resources.getResourceAsStream(resource) 메소드를 통해 resource 변수로 전달된 com/mybatis/Configuration.xml 경로의 파일을 읽어들입니다.
      • 따라서 Configuration.xml 파일은 프로젝트의 classpath에 해당 경로에 위치해 있어야 합니다. 만약 파일 경로가 다르다면, resource 변수를 해당 파일 경로에 맞게 수정해주어야 합니다.
public class DeptServiceImpl implements DeptService{
	static SqlSessionFactory sqlSessionFactory;
    static {
    	String resource = "com/mybatis/Configuration.xml";
    	InputStream inputStream=null;
		try {
			inputStream = Resources.getResourceAsStream(resource);
		} catch (IOException e) {
			e.printStackTrace();
		}
    	sqlSessionFactory =
    	  new SqlSessionFactoryBuilder().build(inputStream);
    }//end static 블럭
    /*
	   SqlSession session = sqlSessionFactory.openSession();
		try {
			
		}finally {
			session.close();
		}
	*/
    1. selectDynamicDeptno 메서드
    • HashMap<String, Integer> 타입의 map 매개변수를 받아 selectDynamicDeptno 메서드를 실행합니다. SqlSession 객체를 생성하여 DeptDAO의 selectDynamicDeptno 메서드를 호출한 후, 반환된 List 타입의 결과를 리턴합니다.

    • List<DeptDTO> list = null;null로 초기화된 List 객체를 생성하는 것입니다.

    • 여기서 null은 아무것도 참조하고 있지 않은 상태를 의미합니다. 따라서 list 변수는 null 상태에서 시작하며, 이후에 코드에서 list에 값이 할당되면서 실제로 참조하게 됩니다.

    • 만약 List<DeptDTO> list;와 같이 초기화를 하지 않고 변수를 선언한 경우, 해당 변수는 아무것도 참조하지 않은 상태이기 때문에 컴파일 오류가 발생할 수 있습니다.

 public List<DeptDTO> selectDynamicDeptno(HashMap<String, Integer> map){
    	 SqlSession session = sqlSessionFactory.openSession();
    	 List<DeptDTO> list = null;
 		try {
 			  DeptDAO dao = new DeptDAO();
 			  list = dao.selectDynamicDeptno(session, map);
 		}finally {
 			session.close();
 		}
    	return list;
    }
    1. selectDynamicChoose 메서드
    • HashMap<String, String> 타입의 map 매개변수를 받아 selectDynamicChoose 메서드를 실행합니다. SqlSession 객체를 생성하여 DeptDAO의 selectDynamicChoose 메서드를 호출한 후, 반환된 List 타입의 결과를 리턴합니다.
    • DeptServiceImpl 클래스에서 SqlSession 객체를 생성하는 이유는, 데이터베이스와의 연결을 확립하고 SQL 쿼리를 실행하기 위해서입니다. SqlSession 객체를 생성하면 데이터베이스와의 연결이 맺어지고, 이를 통해 데이터베이스에 접근하여 SQL 쿼리를 실행할 수 있습니다.
    • , SqlSession을 사용하면 커넥션 풀링, 트랜잭션 관리, SQL 실행 등을 자동으로 처리할 수 있기 때문에, 개발자는 보다 간단하고 편리하게 데이터베이스에 접근할 수 있습니다.
@Override
	public List<DeptDTO> selectDynamicChoose(HashMap<String, String> map) {
		 SqlSession session = sqlSessionFactory.openSession();
    	 List<DeptDTO> list = null;
 		try {
 			  DeptDAO dao = new DeptDAO();
 			  list = dao.selectDynamicChoose(session, map);
 		}finally {
 			session.close();
 		}
    	return list;
	}
    1. updateDynamic 메서드
    • DeptDTO 타입의 dto 매개변수를 받아 updateDynamic 메서드를 실행합니다. SqlSession 객체를 생성하여 DeptDAO의 updateDynamic 메서드를 호출한 후, 결과를 int 타입으로 반환합니다. 이때, session.commit()을 호출하여 트랜잭션을 커밋합니다.
@Override
	public int updateDynamic(DeptDTO dto) {
		 SqlSession session = sqlSessionFactory.openSession();
		 int n = 0;
			try {
				DeptDAO dao = new DeptDAO();
				n = dao.updateDynamic(session, dto);
				session.commit();
			}finally {
				session.close();
			}
		return n;
	}
    1. multiSelect 메서드
    • List 타입의 xxx 매개변수를 받아 multiSelect 메서드를 실행합니다. SqlSession 객체를 생성하여 DeptDAO의 multiSelect 메서드를 호출한 후, 반환된 List 타입의 결과를 리턴합니다.
@Override
	public List<DeptDTO> multiSelect(List<DeptDTO> xxx) {
		SqlSession session = sqlSessionFactory.openSession();
   	 List<DeptDTO> list = null;
		try {
			  DeptDAO dao = new DeptDAO();
			  list = dao.multiSelect(session, xxx);
		}finally {
			session.close();
		}
   	return list;
	}

DeptMain

  • Mybatis를 사용하여 데이터베이스에서 정보를 가져오고 수정하는 방법을 보여주는 예제 코드

  • selectDynamicDeptno 메서드는 매개 변수로 HashMap을 받아 동적 SQL을 실행하고 결과를 DeptDTO의 List로 반환합니다. 이 때 HashMap의 x 키에는 deptno 값이 저장되며, 동적 SQL에서는 이 값을 활용하여 deptno가 x 값인 데이터를 검색합니다.
	//1. selectDynamicDeptno ==> 반드시에 컬렉션 또는 DTO에 저장해야 된다.
		/*
		    select deptno,dname,loc
		    from dept;
		    
		    또는
		    
		    select deptno,dname,loc
		    from dept
		    where deptno = 값;		    
		*/
		
		int deptno = 10;
		HashMap<String, Integer> map =
				new HashMap<>();
		map.put("x", null);
//		map.put("x", deptno);
		
		DeptService service = new DeptServiceImpl();
		List<DeptDTO> list = service.selectDynamicDeptno(map);
		System.out.println(list);
		System.out.println("######################################");
  • HashMap은 Key-Value 쌍으로 데이터를 저장하는 자료구조 중 하나입니다. 이 코드에서는 Key로는 String 타입을, Value로는 Integer 타입을 사용하도록 선언
HashMap<String, Integer> map =
				new HashMap<>();
  • 이 코드를 통해 새로운 HashMap 객체가 생성되고, 이 객체는 Key와 Value가 각각 String과 Integer 타입인 데이터를 저장할 수 있습니다. 이후에는 생성된 HashMap 객체에 put 메소드를 사용하여 데이터를 저장하거나 get 메소드를 사용하여 데이터를 조회


  • selectDynamicChoose 메서드는 매개 변수로 HashMap을 받아 동적 SQL을 실행하고 결과를 DeptDTO의 List로 반환합니다. 이 때 HashMap의 loc 키 또는 dname 키에 저장된 값을 활용하여 동적 SQL에서 조건을 선택합니다.

	//2. selectDynamicChoose
		/*
		    select deptno,dname,loc
		    from dept
		    where dname = 값;   
		
		    select deptno,dname,loc
		    from dept
		    where loc = 값;
		
		   select deptno,dname,loc
		    from dept
		    where loc = 값 and(or) dname=값;
		*/
		HashMap<String, String> map2 =
				new HashMap<>();
//		map2.put("loc", "서울");
//		map2.put("dname", "개발");
		List<DeptDTO> list2 = service.selectDynamicChoose(map2);
		System.out.println(list2);
		
  • 매개 변수로 HashMap을 받아 동적 SQL을 실행한다는 것은, 쿼리 실행 시에 전달되는 파라미터 값이 유동적으로 변하는 상황에서 SQL 문을 동적으로 생성하여 실행한다는 것을 의미합니다.

  • 예를 들어, WHERE 조건에 들어가는 값이 유동적으로 변하는 상황에서, SQL 문을 작성할 때 해당 조건에 대한 값을 동적으로 추가하여 SQL 문을 생성하는 것입니다. 이때 HashMap을 사용하여 파라미터를 전달하면, HashMap의 키와 값으로 쿼리 실행 시 필요한 값을 지정할 수 있습니다.

  • 이러한 방법은 쿼리의 재사용성과 유연성을 높일 수 있습니다. 특히, WHERE 조건에 들어가는 값이 여러 개이거나, 값의 조합에 따라 다른 쿼리를 실행해야 하는 경우에 유용하게 사용할 수 있습니다.

    • 동적이라는 것은, 쿼리 실행 시 필요한 조건이나 값이 실행 시점에 결정되는 것을 말합니다. 예를 들어, 다음과 같은 SQL 문을 생각해 보겠습니다.
      • 아래의 SQL 문에서 employee_id의 값이 정적이므로, 항상 100으로 고정됩니다.
      • 그러나 만약 employee_id의 값이 실행 시점에 결정되어야 하는 경우에는 어떻게 할까요? 이때 동적 SQL을 사용하면 됩니다.
SELECT * FROM employees WHERE employee_id = 100;
  • 동적 SQL은 실행 시점에 파라미터 값을 받아 쿼리를 동적으로 생성하는 것입니다. 예를 들어, HashMap을 사용하여 파라미터 값을 전달하고, 이를 이용하여 실행 시점에 적절한 SQL 문을 생성할 수 있습니다. 즉, employee_id의 값을 HashMap의 값으로 지정하여 쿼리를 실행할 수 있습니다.

  • 동적 SQL을 사용하면, 실행 시점에 필요한 값을 조합하여 SQL 문을 동적으로 생성할 수 있습니다. 이는 쿼리 실행 시 필요한 조건이나 값이 유동적인 경우에 매우 유용합니다.

  • updateDynamic 메서드는 매개 변수로 DeptDTO를 받아 동적 SQL을 실행하고 수정한 데이터의 개수를 반환합니다. 이 때 DeptDTO의 값 중에서 deptno는 고정되어 있으며, loc과 dname은 수정할 값으로 설정됩니다.

	//3. updateDynamic
		/*
		    update dept
		    set loc = 값
		    where deptno = 값;
		    
		    update dept
		    set dname = 값
		    where deptno = 값;
		
		    update dept
		    set dname = 값, loc = 값
		    where deptno = 값;
		
		*/
		DeptDTO dto = new DeptDTO();
		dto.setDeptno(50); //고정
		
		dto.setLoc("LA");
		dto.setDname("영업");
		
		int n = service.updateDynamic(dto);
		System.out.println(n+"개가 수정");


  • multiSelect 메서드는 매개 변수로 DeptDTO의 List를 받아 동적 SQL을 실행하고 결과를 DeptDTO의 List로 반환합니다. 이 때 List에 저장된 DeptDTO의 deptno 값 중에서 일치하는 데이터를 모두 검색하여 반환합니다.
		// 4. 멀티 select -  multiSelect
		/*
		    select *
		    from dept
		    where deptno IN (값,값,...);
		*/
		List<DeptDTO> xxx = 
				 Arrays.asList(new DeptDTO(50,"jjj","ddd"),
						      // new DeptDTO(55,"jjj","ddd"),
						       new DeptDTO(10,"jjj","ddd"));
		
		List<DeptDTO> xxx2 =
				service.multiSelect(xxx);
		System.out.println(xxx2);
  • multiSelect 메서드에서 list를 두 개로 나눈 이유는 MyBatis에서 제공하는 foreach 태그를 사용하기 위해서입니다. foreach 태그는 동적 쿼리를 작성할 때 주로 사용되며, List와 같은 Collection을 입력값으로 받아 해당 Collection의 요소들을 하나씩 꺼내서 쿼리를 실행하는데 사용됩니다.

  • 이 메서드에서는 foreach 태그를 사용하여 SQL 문의 IN 구문에 입력될 파라미터를 동적으로 생성합니다. 첫 번째 리스트(List xxx)는 파라미터로 전달될 DeptDTO 객체의 리스트이며, 두 번째 리스트(List deptnos)는 xxx 리스트에서 추출한 DeptDTO 객체의 deptno 값들만 모아서 만든 리스트입니다.

  • 따라서 이 메서드에서는 foreach 태그가 두 번 사용됩니다. 첫 번째 foreach 태그에서는 xxx 리스트에서 하나씩 DeptDTO 객체를 꺼내서 deptno 값을 추출하여 deptnos 리스트에 저장하게 됩니다. 두 번째 foreach 태그에서는 deptnos 리스트에서 하나씩 deptno 값을 꺼내서 SQL 문의 IN 구문에 입력합니다.

  • 따라서 이 메서드는 입력된 deptno 값들 중 일치하는 데이터를 모두 검색하여 반환합니다. 이를 가능하게 하는 것이 SQL 문의 IN 구문입니다. IN 구문은 WHERE 절에서 사용되며, 주어진 값 중 하나라도 일치하는 경우 해당 레코드를 반환합니다. 이 메서드에서는 xxx 리스트에 입력된 DeptDTO 객체들의 deptno 값들을 추출하여 IN 구문에 입력함으로써 해당하는 레코드를 모두 검색할 수 있게 됩니다.


  • multiDelete 메서드는 매개 변수로 DeptDTO의 List를 받아 동적 SQL을 실행하고 삭제한 데이터의 개수를 반환합니다. 이 때 List에 저장된 DeptDTO의 deptno 값 중에서 일치하는 데이터를 모두 삭제합니다.

  // 5. 멀티 삭제 - multiDelete
	    /*
		    delete from dept
		    wehre deptno IN (값,값,...);
		
		
		*/

JDBC

  • 실행 순서

    jdbc 설정 -> DeptDTO 정의 -> DeptDAO 클래스 작성 -> DeptService 인터페이스 정의 -> DeptServiceImpl 클래스 작성 -> DuplicatedDeptnoException 클래스와 RecordNotFoundException 클래스 정의 -> DeptMain 클래스 작성 및 실행.

    • 먼저, 데이터베이스와 연결하는 JDBC 설정이 완료된다.

    • DeptDTO 클래스를 정의하고, 데이터베이스의 레코드와 일치하는 필드 변수와 생성자, Getter/Setter 메서드를 추가한다.

    • DeptDAO 클래스를 작성하고, 데이터베이스의 CRUD(Create, Read, Update, Delete) 동작을 처리하는 메서드를 추가한다.

    • DeptService 인터페이스를 작성하고, 비즈니스 로직을 정의하는 메서드를 추가한다.

    • DeptServiceImpl 클래스를 작성하고, DeptService 인터페이스를 구현한다. 이 클래스에서는 DeptDAO 클래스의 메서드를 호출하여 데이터베이스와 상호작용한다.

    • DuplicatedDeptnoException 클래스와 RecordNotFoundException 클래스를 정의한다. 이들은 예외 상황에 대응하는 데 사용된다.

  • DeptMain 클래스를 작성하고, 실행 메서드에서 DeptServiceImpl 객체를 생성하여 해당 메서드를 호출한다.
    다음 수행과정을 DTO (Data Transfer Object) 패턴이라고 한다.

  • main( ) : 입출력 화면 처리 & DB연동처리

    • 가장 상위에서 가장 상위의 Service() 인터페이스를 호출

  • Service( ) : 트랜잭션 처리 & main과 DAO 사이의 징검다리

    • DAO의 공통된 메서드를 불러와 main에 전달하는 인터페이스

  • Serviceimple( ) 클래스 : Service( ) 인터페이스를 구현받는 클래스

    • 트랜잭션 단위로 처리하기 위해서, connection 객체 생성

    • 생성한 연결 객체를 DAO의 메서드에 전달

    • 즉, 연결 수행 + DAO의 메서드를 호출 + 연결 종료 후 commit

  • DAO : 실질적으로 DB에 직접 접근하는 클래스

    • DB에 대한 접근하는 메서드를 정의하는 클래스

    • Serviceimple() 클래스에서 전달받은 연결을 이용하여, SQL문을 수행

    • ※ SELECT 문의 경우, 수행결과인 DTO를 한 행 씩 DTO를 담는 리스트에 넣어
      준 다음 이를 Service의 리스트에 반환

  • DTO 클래스 : 데이터를 다른 logic에게 전송 및 반환할 때 효율적으로 데이터를
    전송 및 사용할 수 있게 작성한 클래스

    • DB의 한 행을 저장하기 위한 클래스로, 각 칼럼명을 정의한다.

  • ※ 모든 것을 main클래스에 넣으면, 유지 보수가 어렵고 코드가 복잡하기에
    Service 인터페이스를 생성하여 기능을 분리한다

JDBC 구조 및 개념

  • JDBC DTO 패턴은 데이터베이스의 테이블 구조와 1:1 매핑되는 객체를 사용하여 데이터를 전달하는 패턴입니다. 이 패턴을 사용하면 데이터베이스에 접근하고 데이터를 검색, 추가, 수정, 삭제하는 작업을 쉽게 수행할 수 있습니다. 이 패턴을 사용하기 위해서는 다음과 같은 순서로 작업을 수행해야 합니다.

  • 데이터베이스 테이블의 구조 파악: 데이터베이스 테이블의 구조를 파악하여 각 필드의 이름, 데이터 타입, 제약 조건 등을 확인합니다.

  • DTO 클래스 작성: DTO(Data Transfer Object) 클래스를 작성하여 데이터베이스 테이블의 구조와 1:1 매핑되는 객체를 생성합니다. DTO 클래스에는 데이터베이스 테이블의 각 필드에 대한 멤버 변수가 있어야 하며, 이 멤버 변수들은 private으로 선언되고, getter/setter 메서드를 제공해야 합니다.

  • DAO 클래스 작성: DAO(Data Access Object) 클래스를 작성하여 데이터베이스에 접근하는 메서드를 구현합니다. DAO 클래스에서는 JDBC를 사용하여 데이터베이스에 연결하고, SQL 쿼리를 실행하여 DTO 객체에 데이터를 채워 반환하는 메서드를 작성합니다.

    • JDBC 드라이버 로드: JDBC 드라이버를 로드합니다.
    • 데이터베이스 연결: JDBC를 사용하여 데이터베이스에 연결합니다.
    • SQL 쿼리 실행: DAO 클래스에서 작성한 SQL 쿼리를 실행합니다.
    • DTO 객체에 데이터 저장: SQL 쿼리의 결과를 DTO 객체에 저장합니다.
    • 데이터베이스 연결 해제: 데이터베이스와의 연결을 해제합니다.
    • DTO 객체 반환: DAO 클래스에서 DTO 객체를 반환합니다.
  • 이러한 순서대로 작업을 수행하여 JDBC DTO 패턴을 구현할 수 있습니다.

JDBC 실습 코드 분석

JDBC vs MYBATIS

  • JDBC(Java Database Connectivity)와 MyBatis는 모두 Java에서 데이터베이스와 상호 작용하기 위한 기술입니다.

  • JDBC는 Java에서 데이터베이스와 통신하기 위한 표준 API입니다. JDBC를 사용하면 Java 언어로 구현된 응용 프로그램에서 SQL 쿼리를 실행하고 데이터베이스의 데이터를 검색, 삽입, 업데이트 및 삭제할 수 있습니다. JDBC는 Java의 데이터베이스 연동 기술 중에서 가장 기본적인 기술로, 데이터베이스와 직접적인 연결을 수행합니다.

  • MyBatis는 SQL 매퍼 프레임워크로, JDBC를 기반으로 만들어졌습니다. MyBatis는 SQL을 작성하는 방법을 단순화하고, 데이터베이스 연결 및 트랜잭션 관리 등을 추상화합니다. MyBatis는 SQL 매퍼(XML 파일 또는 어노테이션으로 작성)를 사용하여 SQL을 작성하고 데이터베이스에 대한 연결, 데이터 매핑, 캐싱, 배치 등을 처리합니다. 이를 통해 개발자가 더욱 직관적으로 SQL 쿼리를 작성하고 유지보수할 수 있습니다.

  • 따라서, JDBC는 데이터베이스와 직접적인 연결을 하며, SQL 작성 및 실행을 수동으로 처리해야 하지만, MyBatis는 SQL 매퍼를 사용하여 SQL 작성을 단순화하고, 데이터베이스 연결 및 트랜잭션 관리 등을 자동화합니다.

0개의 댓글