-
Cinephile 스프링 프로젝트 시작(MyBatis)6프로젝트 2020. 9. 14. 00:56
MyBatis가 무엇인가?
'MyBatis는 프레임워크다! JDBC를 보다 편리하게 사용하기 위해 개발 되었다.'
JDBC에서 INSERT, UPDATE, DELETE, SELECT를 할때 DBHelper로 DB에 접속하고 SQL 작업이 끝나면 pstmt 해제, rs 해제, DB 접속해제를 해줘야 했는데 이게 번거롭다! MyBatis에서 그런 처리를 안해도 되게끔 해주게따! 뭐 이런소린가 보다.
이렇단다. 아직 쪼렙 개발자라서 뭔소린지 솔직히 잘 모르겠다.
대충살펴 보면
- 사용 방법이 간단하다
-쉽나보다. - 구조적 강점
-JDBC 작업 처리속도가 빨라지나 보다. - 관심사의 분리
-'리소스를 관리하여 계층화를 지원한다.'는 뭔소린지 모르겠고
-'작업의 분배'는 그런가보다 하겠고
-'SQL문이 애플리케이션 소스코드로부터 완전 분리'는
앞서 JDBC에서 ~~.java 파일에다 sql 스트링 객체에 SQL문을 써놓았던것을 여기선 Mapper.xml 파일에서 수행하겠다는 소리건 알겠고 - 이식성
-아직 잘 모르겠다 - 오픈소스이며 무료다
-음 공짜
앞서 공부했던 DAO의 장,단점과 구조인데 읽어보면 무슨 말인지 대충 이해가 간다. 아래 파란 글씨로 써 놓은 것처럼
'중간 단계인 DAO Interface와 DAO 구현체를 MyBatis가 대신 한다.'고 했는데 이 소리가 JDBC를 편리하게 사용하는 방법 같음.
긍까 JDBC에서 DAO Interface와 DAO 구현체를 사용해 수행했던 작업을 Mapper.xml로 대신할수 있고 pstmt나 rs객체를 따로 만들지 않아도 알아서 해준다는 소리같다. 그래도 DBHelper를 통해서 데이터베이스에 연결하고 해제는 여전히 해야하는것 같다.
첨에는 프레임워크라고 했는데 라이브러리 등록하는거 보니까 라이브러리 형태로 가져다 쓸 수 있는 프레임워크라는 소린가? 좀 헤깔린다.
MyBatis 사용하기
MyBatis의 Mapper.xml이 DAOinterface와 DAO구현체를 대신한다고 했으니까 여전히 Beans와 DBHelper는 필요하다.
1.필요한 DB테이블의 항목에 맞춰 Beans를 만든다.
study.jsva.myschool.model/Department.java(더보기)
더보기package study.java.myschool.model; /** * @File Department.java * @Discription 테이블 구조에 맞춘 자바빈즈 생성 * 기본생성자의 사용을 위해서 파라미터가 포함된 생성자를 생략한다. * @Author 장혁준 newjhj31@gmail.com */ 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 + "]"; } }
※MyBatis에서 파라미터를 갖지않는 생성자를 만들거나 아얘 만들지 말아라
2.MyBatis 설정 파일 준비하기
MyBatis의 DAOinterface와 DAO구현체를 대신하는 Mapper.xml만 필요할 줄 알았는데
-MySQL접속 정보와 Mapper의 경로를 명시한 config.xml이라는 파일도 필요하다.
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="123qwe!@#" /> </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&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>
JDBC에서는 MySQL 접속정보를 DBHelper가 갖고 접속했는데 가만보니 MyBatis에서는 DBHelper를 대신하는 다른게 또 있나보다.
3. DB에 접속하고 SQL을 실행하는 SqlSessionFactory 정의
JDBC의 DBHelper를 대신하는 MyBatis의 SqlSessionFactory.
MyBatisConnectionFactory.java(더보기)
더보기/** * @File MyBatisConnectionFactory.java * @Discription DB에 접속하고 SQL을 실행하는 SqlSessionFactory 정의 * 이 페이지 소스가 DBHelper를 대신 * @Author 장혁준 newjhj31@gmail.com */ 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과 통신하기 위한 접속 단위를 만든것 } }
처음 배웠을때 이거 이해하려고 애먹었는데
'Session은 하나의 통신. 여기서는 Mysql과 통신하기 위한 접속단위를 만드는 것' 이라고 해서
sqlSessionFactory를 하나의 핸드폰 이라고 이해하기로 했다.
만약 어디선가 sqlSessionFactory 객체가 호출된다면 (전화가 온다면) reader를 통해 어떤 값(config.xml)이 할당 되고 (전화를 건사람이 누군지 화면에 표시된다.) sqlSessionFactory.openSession()이 실행된다.(통화하기 버튼을 누른다.) 세션성공! DB에 접속했다 정도 되겠지?(괄호안의
개소리는 오로지 나의 이해를 돕기 위한 것)4. DAOinterface와 DAO구현체를 대신하는 Mapper.xml 작성
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>
DAOinterface와 DAO구현체에서 수행했던 기능들으 보면
DB에 접속해서 SQL문을 수행하고 나온 결과 값을 리턴해 주는 기능을 했는데 여기서는 <>태그 안에 해당 기능들을 써놓고 id를 통해 호출을 하게되면 해당 SQL을 수행하고 나온 결과값을 알아서 처리해 주는것 같다.
INSERT했을때는 '1개의 값이 수정되었다'와 새로 생성된 PK값을 빈즈를 통해서? 알아서 리턴해 주는것 같고
DELETE, UPDATE도 마찬가지
SELECT도 조회된 값을 알아서 빈즈에 저장하는거 같음.
일단 여기까지 해서 MyBatis를 사용할 준비가 끝난것 같다.
다음 이 준비된 MyBatis를 가지고 Main을 수행하겠다
값 입력하기
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 장혁준 newjhj31@gmail.com */ 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(); } }
sqlSession(Main의 핸드폰)은 MyBatisConnectionFactory.java에서 sqlSessionFactory(MyBatis의 핸드폰)와 통신하기위해 필요하다. sqlSession 객체에 MyBatisConnectionFactory.getSqlSession()을 할당하면 (sqlSession에서 sqlSessionFactory로 전화를 걸면) MyBatisConnectionFactory.java를 통해 통신이 시작된다.
sqlSession.insert("DepartmentMapper.add_department",model);은 마치 전화기에 대고 주문을 하는것이다. 'Department매퍼에서 model에 저장된 값을 데이터 베이스에 입력해주세요'라고 그러면 sqlSessionFactory는 주문을 받아 일을 처리해 놓으면 Main에서는 model을 통해 주문이 잘 들어갔는지 result로 확인 할 수 있다.
주문이 완료되었다면 저장하고 끈다.
이렇게 MyBatis에서 입력을 처리하는것 같다.
값 삭제하기
Main02. java
더보기import org.apache.ibatis.session.SqlSession; import study.java.myschool.MyBatisConnectionFactory; import study.java.myschool.model.Department; /** * @File Main01.java * @Discription 학과 정보 삭제하기 * @Author 장혁준 newjhj31@gmail.com */ public class Main02 { public static void main(String[] args) { //1)데이터 베이스 접속 SqlSession sqlSession = MyBatisConnectionFactory.getSqlSession(); //2)삭제할 데이터 --> Main01에서 출력된 값 입력 Department model = new Department(); model.setDeptno(324); //3)데이터 삭제 int result = sqlSession.delete("DepartmentMapper.remove_department", model); //4)결과 판별 System.out.println(result + "개의 데이터 삭제됨"); //5) DB접속 해제 sqlSession.commit(); sqlSession.close(); } }
값 수정하기
Main03.java
더보기import org.apache.ibatis.session.SqlSession; import study.java.myschool.MyBatisConnectionFactory; import study.java.myschool.model.Department; /** * @File Main03.java * @Discription 학과 정보 수정하기 * @Author 장혁준 newjhj31@gmail.com */ public class Main03 { public static void main(String[] args) { // 1)데이터베이스 접속 SqlSession sqlSession = MyBatisConnectionFactory.getSqlSession(); // 2)UPDATE를 수행할 데이터 생성 Department model = new Department(); model.setDeptno(101); model.setDname("인터넷통신학과"); model.setLoc("7호관"); // 3)데이터 수정 int result = sqlSession.update("DepartmentMapper.edit_department", model); // 4)결과 판별 System.out.println(result + "개의 데이터 수정됨"); //5)DB접속 해제 sqlSession.commit(); sqlSession.close(); } }
정보 조회하기
Main04.java
더보기import org.apache.ibatis.session.SqlSession; import study.java.myschool.MyBatisConnectionFactory; import study.java.myschool.model.Department; /** * @File Main04.java * @Discription 학과 정보 단일 데이터 조회 * @Author 장혁준 newjhj31@gmail.com */ public class Main04 { public static void main(String[] args) { // 1) 데이터베이스 접속 SqlSession sqlSession = MyBatisConnectionFactory.getSqlSession(); //2) 조회할 데이터 Department model= new Department(); model.setDeptno(102); //3) 데이터 조회 Department result = sqlSession.selectOne("DepartmentMapper.get_department_item", model); //4) 결과 판별 if(result == null) { System.out.println("조회결과 없음"); }else { System.out.println(result.toString()); } //5) DB접속해제 sqlSession.close(); } }
목록 조회하기
Main05.java
더보기import java.util.List; import org.apache.ibatis.session.SqlSession; import study.java.myschool.MyBatisConnectionFactory; import study.java.myschool.model.Department; /** * @File Main05.java * @Discription 학과 정보 다중조회 * @Author 장혁준 newjhj31@gmail.com */ public class Main05 { public static void main(String[] args) { //1) 데이터베이스 접속 SqlSession sqlSession = MyBatisConnectionFactory.getSqlSession(); //2) 데이터 목록조회 : 파라미터가 필요 없다면 생략 가능 List<Department> result = sqlSession.selectList("DepartmentMapper.get_department_list"); //3) 결과 판별 if( result == null) { System.out.println("조회결과 없음"); }else { for (int i = 0; i< result.size(); i++ ) { Department item = result.get(i); System.out.println(item.toString()); } } //4) DB접속 해제 sqlSession.close(); } }
정리해보면 MyBatis는 JDBC의 DAO패턴을 좀더 쉽게 처리해주는 방법이다. (아직도 프레임워크라고 했을때 이해가 잘..)
DAO인터페이스와 구현체는 Mapper.xml로 대신
DBHelper는 config.xml과 MyBatisConnectionFactory로 대신
빈즈는 그대로
아직까진 이게 편하고 데이터 처리가 빠른지 잘 모르겠지만 그렇다고 하니까 그런줄 알고 있겠다.
'프로젝트' 카테고리의 다른 글
200923 프로젝트 이메일로 인증코드 발송 (3) 2020.09.23 프로젝트 매핑 오류 (0) 2020.09.17 Cinephile 스프링 프로젝트 시작(DAO 패턴)5 (0) 2020.09.13 Cinephile 스프링 프로젝트 시작(PrepareStatement)4 (0) 2020.09.13 Cinephile 스프링 프로젝트 시작(JDBC 복습)3 (0) 2020.09.13 - 사용 방법이 간단하다