JSP 피피티

JSP 피피티 10강 Spring MyBatis

전설의개발자 2020. 9. 3. 17:09

MyBatis를 저번에 배웠음에도 불구 하고 MyBatis가 뭐냐고 누가 묻는다면 나는 명확하게 이거다! 라고 말을 못한다. 확실하게 개념이 잡히지 않았기 때문!! 인터넷에 MyBatis는 ~~다 라고 설명은 되어있지만 이해가 잘 되지 않는다. 그래도 나만의 개념을 잡아 볼 수 있도록 노력해야 겠다.

MyBatis란?

JDBC를 보다 편리하게 사용하기 위해 개발된 프레임워크

-JDBC 프로그램의 단점 
1.세부적인 작업이 가능하도록 작업별로 각가의 메소드를 호출해야 한다.

2.이는 다수의 메소드를 호출하고 관련된 객체를 해제하는 과정을 거친다.

Mybatis 정의

Mybatis는 개발자가 지정한 SQL, 저장 procedure 그리고 몇가지 고급 매핑을 지원하는 persistance 프레임워크이다.

Mybatis는 JDBC로 처리하는 상당부분의 코드와 파라미터 설정 및 결과 매핑을 대신해준다. Mybatis는 데이터베이스 레코드에 원시타입과 Map 인터페이스 그리고 자바 POJO 를 설정해서 매핑하기 위해 XML과 애노테이션을 사용할 수 있다.

 

일단 선생님 PPT에 나온 설명과 인터넷에서 찾은 건데 여기서 알 수 있는 것은 MyBatis가 프레임워크라는 것, JDBC를 대신하는 것이다. 

 

JDBC는 무엇인가?(더보기클릭)

더보기

자바 프로그램 안에서 SQL을 실행하기 위해 데이터베이스를 연결해주는 응용프로그램 인터페이스를 말한다.

JDBC 지도

Main01은 DBHelper.java고 나머지 Main들은 insert, delete, update, select등을 수행한 것

내가 JDBC라고 해서 배웠던 코드를 보면

 

DBHelper.java

package study.java.helper;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * @File DBHelper.java
 * @Discription 재사용을 필요로하는 코드  helper 만들기 
 * @Author 
 */
public class DBHelper {
	
	//데이터베이스에 접속하기 위한 정보 정의하기
	private static final String db_hostname = "localhost";
	private static final int db_portnumber = 3306;
	private static final String db_database = "myschool";
	private static final String db_charset = "utf8";
	private static final String db_username = "root";
	private static final String db_password = "564wee*^#";	
	
	private Connection conn = null;
	//------싱글톤 객체 생성 시작 ----------
		private static DBHelper current; //싱글톤객체 선언!! 다른 매서드들과 관계없는 독립적인 객체
		public static DBHelper getInstance() {
			if(current == null) {
				current = new DBHelper();
			}
			return current;
		}


		public static void freeInstance() {
			//객체에 null을 대입하면 메모리에서 삭제된다.
			current = null;
		}

		//기본생성자를 private로 은닉하게 되면 new를 통한 객체 생성이 금지된다.
		private DBHelper() {
			super();
		}
		//------싱글톤 객체 생성 끝 -----------
		
		/** 데이터베이스에 접속후, 접속 객체를 리턴한다.*/
		public Connection open() {
			//중복 실행될 경우 발생될 문제를 방지하기 위하여,
			//Connection 객체가 null인 경우만 처리하도록 if문으로 구성
			if(conn == null) {
				/**데이터 베이스 접속처리 */
				//사용하려는 데이터베이스명을 포함한 URL기술
				// --> jdbc:mysql://localhost:3306/myschool?characterEncoding=utf8&serverTimezone=UTC
				String urlFormat = "jdbc:mysql://%s:%d/%s?characterEncoding=%s&serverTimezone=UTC";
				String url = String.format(urlFormat, db_hostname, db_portnumber,
							db_database, db_charset);
				 
				
				//MySql JDBC의 드라이버 클래스를 로딩해서 DriverManager클래스에 등록한다.
				//접속과정에서 예외처리가 요구된다.
				try {
					//MySQL JDBC의 드라이버 클래스를 로딩해서 DriverManager클래스에 등록한다.
					Class.forName("com.mysql.cj.jdbc.Driver");
					//이클립스에서 내장 되어있는 클래스
					
					
					//DriverManager 객체를 사용하여 DB에 접속한다.
					//-> 접속URL, 아이디, 비밀번호를 전달
					//-> DriverManager에 등록된 Driver 객체를 사용하여 DB에 접속 후, 
					// Connection 객체를 리턴받는다.
					//-->import java.sql.DriverManager 필요함
					conn = DriverManager.getConnection(url, db_username, db_password); //명령 프롬프트에서 하는것 과 같다.
					
					//성공메세지 출력
					System.out.println("===DATABASE Connect Success===");
				}catch(ClassNotFoundException e) {
					//실패시 메시지와 에러내용 출력
					System.out.println("===DATABASE Connect Fail===");
					System.out.println(e.getMessage());
				}catch(SQLException e) {
					//실패시 메시지와 에러내용 출력
					System.out.println("===DATABASE Connect Fail===");
					System.out.println(e.getMessage());
				}
			}
			
			return conn;
		}
		
		/**데이터베이스의 접속을 해제한다. */
		public void close() {
			if(conn != null) {
				/**데이터베이스 접속 해제 처리*/
				try {
					conn.close();
					System.out.println("===DATABASE Disconnect Success===");
				}catch(Exception e) {
					System.out.println("===DATABASE Disconnect Fail===");
					System.out.println(e.getMessage());
				}
				conn = null;
			}
		}
		
}

이 위에 있는 코드는 JAVA에서 데이터베이스에 접속하고 해제하는 코드고 이 다음부터 나올 자바를 통해 데이터베이스 질의문을 수행하기 위한 코드들을 사용하기 위해서 필요하다.

 

Main02.java

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import study.java.helper.DBHelper;

/**
 * @File Main02.java
 * @Discription 데이터 추가!!
 * @Author 
 */
public class Main02 {

	public static void main(String[] args) {
		// 'department' 테이블에 `컴퓨터정보과` 추가하기 위한 SQL
		String sql = "INSERT INTO department (deptno, dname, loc) VALUES (300, '컴퓨터정보과', '5호관')";
		
		/** DBHelper를 통한 DB 접속 처리*/
		DBHelper db = DBHelper.getInstance();
		Connection conn = db.open(); //helper에서 연결된 거를 여기와서 conn형태로 넘겨 받음
		
		/**SQL 구문 실행하기*/
		//SQL문을 실행할 수 있는 객체
		Statement stmt = null; //Statement 형 stmt에 널값을 주었다.
		//결과값 (저장된 데이터의 수)
		int result = 0;
		
		try {
			//SQL문을 실행할 수 있는 객체 생성(예외처리 요구됨)
			stmt = conn.createStatement();
			//SQL문 실행하기 --> 결과 행 리턴 됨(예외처리 요구됨) 
			result = stmt.executeUpdate(sql);
		}catch (SQLException e) {
			System.out.println("MySQL SQL Fail : " + e.getMessage());
		}finally {
			//SQL 구문의 에러 여부에 상관 없이 stmt 객체를 닫기 위하여 finally 블록 사용.
			//-> 객체의 유효범위 설정을 위해서 stmt 객체는 try 블록 밖에 선언되었다.
			
			//JDBC관련 객체들은 사용이 완료된 후에는 반드시 close 처리를 수행해야 한다.
			//이떄, 생성된 순서의 역순으로 처리한다.
			if(stmt != null) {
				// 객체 닫기
				try {
					stmt.close();
				}catch(SQLException e) {}
			}
		}
		
		//결과출력
		System.out.println(result + " Record Insert");
		
		
		/**DB 접속 해제*/
		db.close();
	}

}

위의 코드는 자바에서 데이터베이스에 접속하여 값을 넣는 작업(insert)을 진행한다.

위에서 보면 은 JDBC로 데이터베이스에 INSERT 한 번 하려고 Helper를 사용해서 db에 연결하고 Main02에서 INSERT하고 연결해제를 해야 하는데 이게 번거로 울 수 있다는 소리같음

 

==========================JDBC 설명 끝=========================

 

마이바티스 지도

마이바티스가 프레임워크라고 했으니까 src폴더에

  • (default package)         
    ---> 각종 sql구문 실행을 요청하는 코드
  • study.java.myschool   
    ---> config.xml=db접속정보 및, Mapper경로 지정/ MyBatisConnectionFactory.java=JDBC에서 DBHelper 대신
  • study.java.myschool.mapper
    ---> 질의문(SQL)명시 
  • study.java.myschool.model
    ---> 값을 담을 Beans

 

갑자기 프레임워크란??? (더보기클릭)

더보기

프레임워크는 공장과 같습니다. 

옷 공장, 신발 공장, 만두 공장 등 공장마다 서로다른 제품을 생산합니다.

제품을 만들기 위해 어던 재료를 사용 하냐에 따라 같은 제품일지라도 품질, 디자인 등 여러 면이 달라집니다.

하지만 공장이라는 개념을 봤을 경우 공장은 재료를 준비하고 가공하고 생산하는 일은 같은 원리입니다.

 

프레임워크도 같은 개념입니다. 애플리케이션을 구축 할 때 모든 애플리케이션의 공통적인 부분을 제공해줍니다.

 

예를들면 웹 애플리케이션을 구축한다고 예를 들겠습니다.

웹 애플리케이션을 구축하려면 우선 웹에 맞는 환경설정과 DB에 연결하는 부분, 사용자에게 보여주는 부분 등 모든 웹 애플리케이션의 공통적인 부분입니다. 이런 부분을 제공해주는 것이 프레임워크입니다. 

그렇다보니 애플리케이션 구축 시간이 빨라지며 비용이 절감됩니다.

============================프레임워크설명끝============================

그래서 MyBatis 프레임워크는 Model, mapper, config.xml, connectionFactory 가 기본적으로 필요한듯. 

Department.java

더보기
package study.java.myschool.model;

/**
 * @File Department.java
 * @Discription 테이블 구조에 맞춘 자바빈즈 생성 
 * 				기본생성자의 사용을 위해서 파라미터가 포함된 생성자를 생략한다.
 * @Author
 */
public class Department {
	private int deptno;
	private String dname;
	private String 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 "Department [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc + "]";
	}	
}

DepartmentMapper.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">

<!-- 이 XML의 구조대로 구현될 클래스의 이름 => Impl클래스를 대체한다. -->
<mapper namespace="DepartmentMapper">

	<!-- Beans 클래스의 객체이름(id)과 클래스이름(type)을 명시한다 여기선 Department 타입. -->
	<resultMap id="department" type="study.java.myschool.model.Department">
		<!-- Beans의 멤버변수(property)이름과 대상 테이블의 컬럼(column)을 연결한다. -->
		<result property="deptno" column="deptno" />
		<result property="dname" column="dname" />
		<result property="loc" column="loc" />
	</resultMap> <!-- (select를 호출했을때 쓰기 위해)↑↑ 리턴될 Beans의 이름 -->

	<!--
		데이터 저장을 위한 기능 정의
		<insert id="메서드이름에 해당하는 식별자" <여러가지 조건을 가진 insert가 있을 수 있다. 그것을 id로 식별> 
				parameterType="파라미터의 데이터 타입(Beans의 클래스명)" 
				useGeneratedKeys="자동증가 일련번호값 리턴 여부" 
				keyProperty="자동증가 일련번호 컬럼명">
	-->
	<insert id="add_department" 
	    	parameterType="study.java.myschool.model.Department" 
	    	useGeneratedKeys="true"
	    	keyProperty="deptno">
		<!-- "#{변수명}" 으로 표시된 곳에 Beans의 멤버변수가 치환된다. -->
		INSERT INTO department (dname, loc) VALUES (#{dname}, #{loc});
	</insert>

	<!--
		데이터 삭제를 위한 기능 정의
		<delete id="메서드이름에 해당하는 식별자" 
				parameterType="파라미터의 데이터 타입(Beans의 클래스명)">
	-->
	<delete id="remove_department" 
	    	parameterType="study.java.myschool.model.Department">
		<!-- "#{변수명}" 으로 표시된 곳에 Beans의 멤버변수가 치환된다. -->
		DELETE FROM department WHERE deptno=#{deptno};
	</delete>

	<!--
		데이터 갱신을 위한 기능 정의
		<update id="메서드이름에 해당하는 식별자" 
				parameterType="파라미터의 데이터 타입(Beans의 클래스명)">
	-->
	<update id="edit_department" 
	    	parameterType="study.java.myschool.model.Department">
		<!-- "#{변수명}" 으로 표시된 곳에 Beans의 멤버변수가 치환된다. -->
		UPDATE department SET dname=#{dname}, loc=#{loc} 
		WHERE deptno=#{deptno};
	</update>

	<!--
		단일행 조회를 위한 기능 정의
		<select id="메서드이름에 해당하는 식별자"
				parameterType="파라미터의 데이터 타입(Beans의 클래스명)" 
				resultMap="리턴될 Beans이름">
	-->
	<select id="get_department_item" 
	    	parameterType="study.java.myschool.model.Department" 
	    	resultMap="department">
		<!-- "#{변수명}" 으로 표시된 곳에 멤버변수가 치환된다. -->
		SELECT deptno, dname, loc FROM department WHERE deptno=#{deptno};
	</select>

	<!--
		다중행 조회를 위한 기능 정의
		<select id="메서드이름에 해당하는 식별자" 
				resultMap="리턴될 Beans이름">
	-->
	<select id="get_department_list" resultMap="department">
		<!-- 이 안에서 처리할 SQL문을 명시한다. -->
		SELECT deptno, dname, loc FROM department;
	</select>
	
</mapper>

config.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>
	<!-- MySQL 접속 정보를 지정한다. -->
    <properties>
        <property name="hostname" value="localhost" />
        <property name="portnumber" value="3306" />
        <property name="database" value="myschool" />
        <property name="username" value="root" />
        <property name="password" value="185684#" />
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://${hostname}:${portnumber}/${database}?characterEncoding=UTF8&amp;serverTimezone=UTC" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 실행할 SQL문을 정의한 Mapper XML의 경로를 지정한다. -->
	<mappers>
		<mapper resource="study/java/myschool/mapper/DepartmentMapper.xml" />
		<mapper resource="study/java/myschool/mapper/ProfessorMapper.xml" />
		<mapper resource="study/java/myschool/mapper/StudentMapper.xml" />
	</mappers>
</configuration>

MyBatisConnectionFactory.java

더보기
/**
 * @File MyBatisConnectionFactory.java
 * @Discription DB에 접속하고 SQL을 실행하는 SqlSessionFactory 정의
 * 				이 페이지 소스가 DBHelper를 대신
 * @Author 
 */
package study.java.myschool;

import java.io.IOException;
import java.io.Reader;

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

//!!!!!!!!!!!!!!!DBHelper를 대신하는 페이지

public class MyBatisConnectionFactory {
	/**데이터베이스 접속 객체*/
	//import org.apache.ibatis.session.SqlSessionFactory;
	private static SqlSessionFactory sqlSessionFactory;
	//sql 본부??? 
	
	//↓↓↓↓ 무전기 켜는 순간 주파수 설정
	/**XML에 명시된 접속 정보를 읽어 들인다.*/
	//클래스 초기화 블럭 : 클래스 변수의 복잡한 초기화에 사용된다.
	//클래스가 처음  로딩될때 한번만 수행된다.
	//↓↓(static)복잡한 변수를 초기화 할때 씀.. 잘 안쓰임
	static {
		//접속 정보를 명시하고 있는 XML의 경로 읽기
		// --> import java.io.Reader;
		// --> import org.apache.ibatis.io.Resources;
		try {
			Reader reader = Resources.getResourceAsReader(
					"study/java/myschool/config.xml"); //reader를 통해서 config.xml을 가져와			
			
			//sqlSessionFactory가 존재하지 않는다면 생성한다.
			if(sqlSessionFactory == null) {
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**데이터베이스 접속 객체를 통해 DATABASE에 접속한 세션을 리턴한다.*/
	//--> import org.apache.ibatis.session.SqlSession;
	public static SqlSession getSqlSession() {
		return sqlSessionFactory.openSession(); //<-- myschool을 열어주는 기능
		//↑↑↑SqlSession 이라는 객체를 리턴 Session 은 하나의 통신 여기서는 
		//MySQL과 통신하기 위한 접속 단위를 만든것
	}

}

 

Main01.java

더보기
import org.apache.ibatis.session.SqlSession;

import study.java.myschool.MyBatisConnectionFactory;
import study.java.myschool.model.Department;

/**
 * @File Main01.java
 * @Discription 마이바티스를 통해 값을 인서트하기
 * 			정의된 Mapper 를 호출하기 위한 과정 살펴보기
 * 			데이터베이스 접속과 저장될 데이터 준비
 * 			데이터베이스에 저장될 데이터를 Beans로 묶는다.
 * 			이 Beans 객체가 SqlSession 객체에게 전달되어
 * 			Mapper XML에 명시된 SQL문에 설정될 것이다.
 * @Author 
 */
public class Main01 {

	public static void main(String[] args) {
		// 1) 데이터베이스 접속
		//--> import study.java.myschool.MyBatisConnectionFactory;
		//--> import org.apache.ibatis.session.SqlSession;
		//Session은 하나의 통신!! 여기서는 Mysql과 통신하기 위한 접속단위를 만든것
		SqlSession sqlSession = MyBatisConnectionFactory.getSqlSession(); 
		// ↑↑↑↑명령프롬프트에서 myschool DB에 접속하는 과정 SQL명령문 쓰기 전
		//자바와 MySQl 서로 다른 프로그램 사이에서 서로 통신하기위한 최소단위session 이게 있어야만 서로 통신가능
		//↑↑↑↑ 자바에서 SQL에 통신시도
		
		
		// 2) INSERT를 수행할 데이터 생성
		// -->Beans에 생성자를 정의하지 않으면 필요한
		// 		데이터만 setter로 추가 할 수 잇다.
		// -->import study.java.myschool.model.Department;
		Department model = new Department();
		model.setDname("JAVA학과");
		model.setLoc("공학관");
		//이때 deptno 값은 0이다.
		
		
		// 3) 데이터 저장
		//DepartmentMapper라는 namespace(패키지)를 갖는 XML에서 
		//id값이 add_department인 <insert> 태그를 호출한다.
		sqlSession.insert("DepartmentMapper.add_department", model);
		//config에 경로를 표시하는 구문(config 의 <Mapper>)에 여러가지 경로가 있을수 이따. 그래서 위에 파일이름을 써줌
		//insert는 반환형이 없어서 이렇게 해도 실행이 되는 데 결과(deptno 값)를 알고싶어 아래 result에 대입출력
		//이 때, 저장할 데이터를 담고 있는 Beans를 파라미터로 전달하고,
		//자동으로 생성된 PK(Primary Key)기본키는 BEANS에 저장된다.
		int result = model.getDeptno();
		
		// 4) 결과 판별
		//-->리턴값이 0이라면 내부적으로 예외가 발생된 상황으로 간주해야 한다.
		System.out.println(result + "번 데이터 저장됨");
		
		// 5) DB접속 해제
		//페이지 종료 전에 데이터의 변경사항을 저장(commit)하고 
		//데이터베이스 접속해제
		sqlSession.commit(); //commit은 완전히 연산을 끝냈다 DB에 실제로 반영해라.라는 명령어!!
		sqlSession.close();
		
	}

}

 


스프링에서 MyBatis 기본세팅!

일단 pom.xml에 JDBC와 MyBatis에 대한 의존성을 설정한다. 필요 Depedency 5개 pom.xml에 추가하기 

pom.xml

<!-- MySQL Connector ( 2020-08-24기준 최신버전 ) -->
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.21</version>
		</dependency>
		
		<!-- MyBatis ( 2020-08-24기준 최신버전 ) -->
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.5</version>
		</dependency>
		
		<!-- Log4Jdbc Log4j2 JDBC 4 1(2020-08-24 기준 최신버전) -->      
		<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
			<version>1.16</version>
		</dependency>
		
		<!-- Spring JDBC -->
		<!-- httpd://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		
		<!-- Spring Mybatis -->
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>2.0.3</version>
		</dependency>
	

 

MyBatis와 Log4j의 연동 설정 

Log4j.xml 에 아래코드 추가

<!-- DATABASE 연동 관련 로그 설정 시작 -->
	<logger name="org.apache.ibatis">
		<level value="DEBUG"/>
	</logger>
	<logger name="jdbc.sqlonly">
		<level value="INFO"/>
	</logger>
	<logger name="jdbc.sqltiming">
		<level value="OFF"/>
	</logger>
	<logger name="jdbc.audit">
		<level value="OFF"/>
	</logger>
	<logger name="jdbc.resultset">
		<level value="ERROR"/>
	</logger>
	<logger name="jdbc.resultsettable">
		<level value="DEBUG"/>
	</logger>
	<logger name="jdbc.connection">
		<level value="ERROR"/>
	</logger>
	<logger name="log4jdbc.debug">
		<level value="ERROR"/>
	</logger>
	<!-- DATABASE 연동 관련 로그 설정 끝 -->

log4jdbc.log4j2.properties <<이 파일은 새로 만들고

log4jdbc.auto.load.popular.drivers=false
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0

log4jdbc.debug.stack.prefix=sql
log4jdbc.sqltiming.warn.threshold=0
log4jdbc.sqltiming.error.threshold=0
log4jdbc.dump.booleanastruefalse=false
log4jdbc.dump.fulldebugstacktrace=false
log4jdbc.statement.warn=false
log4jdbc.dump.sql.select=true
log4jdbc.dump.sql.insert=true
log4jdbc.dump.sql.update=true
log4jdbc.dump.sql.delete=true
log4jdbc.dump.sql.create=true
log4jdbc.dump.sql.addsemicolon=false
log4jdbc.trim.sql=true
log4jdbc.trim.sql.extrablanklines=true
log4jdbc.suppress.generated.keys.exception=false

root-context.xml 에 이 구문 추가하기

<!-- DB연동에 필요한 환경설정 값 -->
	<util:properties id="dbConfig">
		<!-- 데이터베이스 호스트 이름 -->
		<prop key="dbHost">localhost</prop>
		<!-- 데이터베이스 포트번호 -->
		<prop key="dbPort">3306</prop>
		<!-- 데이터베이스 이름 -->
		<prop key="dbName">myschool</prop>
		<!-- 데이터베이스 문자셋 -->
		<prop key="dbCharset">utf8</prop>
		<!-- 데이터베이스 계정명 -->
		<prop key="dbUsername">root</prop>
		<!-- 데이터베이스 비밀번호 -->
		<prop key="dbPassword">sdfsfs#</prop>
		<!-- Mapper 파일들이 위치할 '/src/main/resource' 하위의 경로 -->
		<prop key="mapperPath">/mappers/**/*Mapper.xml</prop>
	</util:properties>
    
    
    	<!-- ======= DATABASE 연동 설정 ======= -->
	<!-- JDBC 객체 생성 -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" name="driverClassName"/>
		<property value="jdbc:log4jdbc:mysql://#{dbConfig['dbHost']}:#{dbConfig['dbPort']}/#{dbConfig['dbName']}?characterEncoding=#{dbConfig['dbCharset']}&amp;serverTimezone=UTC" name="url"/>
		<property value="#{dbConfig['dbUsername']}" name="username"/>
		<property value="#{dbConfig['dbPassword']}" name="password"/>
	</bean>

	<!-- SQLSessionFactory 객체 생성 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- JDBC 객체를 dataSource에 대한 setter 메서드를 통해 주입 -->
		<property name="dataSource" ref="dataSource"/>
		<!-- MyBatis Mapper 파일들에 대한 경로 패턴 주입 -->
		<property value="classpath:#{dbConfig['mapperPath']}" name="mapperLocations"/>
	</bean>

	<!-- SQLSession 객체 생성. 이 객체가 Service 패턴에 주입된다. -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
		<!-- 생성자를 통해 SQLSessionFactory 객체 주입 -->
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
    

스프링에서 MyBatis 사용하기!

MyBatis 지도에서 처럼(더보기클릭)

 

1.테이블 구조를 명시한 POJO클래스 정의(model)

src/main/java/study.psring.simplespring.model/Department.java

package study.spring.practicespring.model;

import lombok.Data;

/*테이블 구조에 맞춘 Java Beans 생성*/
@Data
public class Department {
	private int deptno;
	private String dname;
	private String loc;
}

2.하나의 테이브에서 이루어져야하는 기본 CRUD 기능 (Mapper)

src/main/resources/mappers/DepartmentMapper.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="DepartmentMapper">

	<!-- Beans 클래스의 객체이름(id)과 클래스이름(type)을 명시한다. -->
	<resultMap type="study.spring.practicespring.model.Department" id="departmentMap">
		<!-- Beans의 멤버변수(property)이름과 대상 테이블의 컬럼(column)을 연결한다. -->
		<result column="deptno" property="deptno"/>
		<result column="dname" property="dname"/>
		<result column="loc" property="loc"/>
	</resultMap>

	<!-- 단일행 조회를 위한 기능 정의 -->
	<select id="selectItem" resultMap="departmentMap" parameterType="study.spring.practicespring.model.Department">
	SELECT deptno, dname, loc FROM department WHERE deptno=#{deptno}; 
	</select>

	<!-- 다중행 조회를 위한 기능 정의 -->
	<select id="selectList" resultMap="departmentMap" parameterType="study.spring.practicespring.model.Department">
	SELECT deptno, dname, loc FROM department 

	<where>
		<if test="dname != null and dname != ''">
		dname LIKE concat('%', #{dname}, '%') 
		</if>
		<if test="loc != null and loc != ''">
		OR loc LIKE concat('%', #{loc}, '%') 
		</if>
	</where>
	ORDER BY deptno DESC 
	</select>

	<!-- 데이터 저장을 위한 기능 정의 -->
	<insert id="insertItem" 
		parameterType="study.spring.practicespring.model.Department" 
		keyProperty="deptno" 
		useGeneratedKeys="true">
	INSERT INTO department (dname, loc) VALUES (#{dname}, #{loc}); 
	</insert>

	<!-- 데이터 삭제를 위한 기능 정의 -->
	<delete id="deleteItem" 
		parameterType="study.spring.practicespring.model.Department">
	DELETE FROM department WHERE deptno=#{deptno}; 
	</delete>
	

	
	<!-- 데이터 갱신을 위한 기능 정의 -->
	<update id="updateItem" 
		parameterType="study.spring.practicespring.model.Department">
	UPDATE department SET dname=#{dname}, loc=#{loc}
	WHERE deptno=#{deptno}; 
	</update>

	<!-- 데이터 수 조회하기 -->
	<!-- 조건에 맞는 데이터 수를 집계하여 int 타입으로 반환한다. 
	count, max, min, sum, avg 함수를 사용한 경우 Mapper에서는
	resultMap이 아닌 resultType으로 반환한다. -->
	<select id="selectCountAll" 
		parameterType="study.spring.practicespring.model.Department" 
		resultType="int">
	SELECT COUNT(*) FROM department 

	<where>
		<if test="dname != null and dname != ''">
		dname LIKE concat('%', #{dname}, '%') 
		</if>
		<if test="loc != null and loc != ''">
		OR loc LIKE concat('%', #{loc}, '%') 
		</if>
	</where>

	</select>

</mapper>

 

 MyBatis지도에서 보이는 confg.xml과 MyBatisConnectionFactory.java의 코드들은 위에 root-context.xml에서 쓴거같다.

 

이제 남은건 Main에 작성된 기능인데 이 기능을할 코드를 쓰기전 단위테스트(Junit)라고 전체 프로그램을 실행하지 않고도 특정 기능의 정상 동작 여부를 확인하는 과정을 거친다.

 

MyBatis를 통해 데이터 입출력 구현에 앞서 트랜젝션이라는 개념을 알고 넘어가자 

트랜젝션

데이터베이스 내에서 한꺼번에 수행되어야 할 일련의 연산/ 트랜젝션의 모든 연산은 반드시 한꺼번에 완료 되거나 그렇지 않은경우 한꺼번에 취소 되어야 한다. 
-한꺼번에 완료된 경우 COMMIT, 취소가 된 경우 ROLLBACK

 

MyBatis에서의 트랜젝션

INSERT, UPDATE, DELETE와 같이 데이터가 직접적으로 변경되어야 할 경우 MyBatis가 자동으로 수행하는 처리로서,

전체가 성공된 경우 실제 저장을 할지 - 처리도중 예외가 발생한 경우 수행을 되돌릴지를 결정하는 처리 및 그 단위를 말한다.

 

집계함수를 사용한 데이터 조회

 

Join문 사용하기

Join문의 결과를 적용할 Beans 클래스 정의

ProfessorDepartment.java

package study.spring.practicespring.model;

import lombok.Data;
//join문에서 출력하는 필드들을 저장해야 하므로 
//join문의 결과에 멤버변수들을 맞춰 정의한다.
@Data
public class ProfessorDepartment {
	private int profno;
	private String name;
	private String userid;
	private String position;
	private int sal;
	private String hiredate;
	private int comm;
	private int deptno;
	private String dname;
	private String loc;
}

join문에서 출력하는 필드들을 저장해야 하므로 join문의 결과에 멤버변수들을 맞춰 정의한다.

 

ProfessorDepartmentMapper.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="ProfessorDepartmentMapper">
	<!-- Beans 클래스의 객체이름(id)와 클래스이름(type)을 명시한다. -->
	<resultMap id="professorDepartmentMap"
		type="study.spring.practicespring.model.ProfessorDepartment">
		<!-- Beans의 멤버변수 (property)이름과 대상 테이블의 컬럼(column)을 연결한다. -->
		<result property="profno" 	column="profno" />
		<result property="name" 	column="name" />
		<result property="userid" 	column="userid" />
		<result property="position" 	column="position" />
		<result property="sal" 	column="sal" />
		<result property="hiredate" 	column="h_date" />
		<result property="comm" 	column="comm" />
		<result property="deptno" 	column="deptno" />
		<result property="dname" 	column="dname" />
		<result property="loc" 	column="loc" />	
	</resultMap>
	
	<!-- Join 결과를 반환 -->
	<select id="selectJoin"
		parameterType="study.spring.practicespring.model.ProfessorDepartment"
		resultMap="professorDepartmentMap">
		SELECT
			profno, name, userid, position, sal,
			date_format(hiredate, '%Y-%m-%d') as h_date,
			comm, p.deptno, dname, loc
		FROM professor as p
		INNER JOIN department as d
		ON p.deptno = d.deptno
		
		<where>
			<if test="dname != null and dname != ''">
				dname LIKE concat('%', #{dname}, '%')
			</if>
			
			<if test="loc != null and loc != ''">
				OR loc LIKE concat('%', #{loc}, '%')
			</if>
		</where>
		</select>
	
</mapper>

resultMap은 select문의 결과에 대해서만 관련있다. select에서 조회되는 컬럼에 별칭을 사용한다면 그 별칭을 명시한다.

아무튼 스프링의 MyBatis는 이런식