ㅁ main.jsp를 아래와 같이 작성한다.
- 스프링 넘어가서도 마이바티스는 활용하니 그때 더 많은 기능을 써보기로 한다.
ㅁ MyBatis 홈페이지에 접속한다.
- 마이바티스에서 제공하는 클래스들이 있다. 그 클래스들을 이용해서 CRUD를 진행한다.
그러기 위해서는 마이바티스 라이브러리가 필요하다.
- 프레임워크 공식 사이트는 항상 북마크한다.
- 항상 이런 공식 사이트에는 get started(시작하기)가 있다.
- 마이바티스를 사용하기 위해서는 mybatis-x.x.x.jar 파일을 넣어야 한다. jar 파일이 곧 라이브러리다.
- 스프링에 들어가면 라이브러리를 관리하는 maven을 사용한다.
그럼 굳이 이 파일을 다운받아서 직접 넣을 필요는 없다.
maven 관련 문서에 저 dependency태그 5줄만 쓰면 된다.
- 지금은 직접 다운받는다. mybatis-x.x.x.jar를 누르면 깃으로 이동된다.
- x 부분은 버전이다. 항상 최신버전은 안받는게 좋다.
- 3.5.14 버전으로 한다. Assets를 눌러서 mybatis-3.5.14.zip파일을 받는다.
- 스프링 버전에 따라서 마이바티스는 몇버전을 써야 좋은 그런게 있다. 호환성이 다르다.
- zip파일의 압축을 풀고, mybatis-3.5.14.jar파일만 c:\dev와 src/main/webapp/WEB-INF/lib폴더에 가져다둔다.
- 깃으로 프로젝트를 올릴 때 jar 파일은 안올라간다. jar 파일은 공유하지 않는다.
집에가면 jar 파일은 따로 받아야 한다. 구글드라이브 lib폴더에 사용하고있는 jar파일들 다 모여있다.
ㅁ 다시 마이바티스의 시작하기 페이지로 돌아온다.
- 시작하기 페이지에서 아래로 내린다.
- 위의 화면에서 두번째 박스는 Java 코드고 세번재 박스는 xml 코드다.
- 접속할 db에 대한 정보를 기존에는 driver.properties에 작성했는데 이제는 xml 파일에 작성한다.
- XML 파일은 MyBatis가 DB에 어떻게 연결할지 설정하는 파일이다.
DB 접속 정보(드라이버, URL, 사용자명, 비밀번호)와 트랜잭션 설정, 사용할 SQL 매퍼 파일 경로 등이 담겨 있어서, MyBatis가 DB와 상호작용할 수 있도록 도와주는 역할이다.
- 자바 코드는 XML 파일(MyBatis 설정 파일)을 읽어와서 데이터베이스에 연결(DB 연동)한다.
ㅁ mybatis-config.xml 파일을 만들어서 접속할 db에 대한 정보를 기술한다.
- 근데 저 파일은 "일반 폴더"가 아닌 "소스 폴더"에 위치해야 한다.
db환경설정 관련한 부분들은 소스폴더에 작성한다.
- 지금 소스폴더는 src/main/java가 있는데 여기에 두지 않고 소스폴더를 새로만든다. resources라는 이름으로 만든다.
- resources라는 이름으로 만든 이유는 스프링 프로젝트하면 마이바티스 관련 환경설정 문서들을 보관할 폴더를 resources라는 이름으로 소스폴더가 자동으로 만들어진다.
- 프로젝트 아래에 바로 resources라는 소스폴더를 만든다.
소스폴더 resources 안에 "config"와 "mappers"라는 일반 폴더를 만든다.
- 환경설정 문서는 config 폴더에, mapper 파일(쿼리문)들은 mappers 폴더에 둘 예정이다.
ㅁ config 폴더 우클릭 - xml 파일 생성
- 다른 이름도 상관없는데 보통 mybatis관련 환경설정을 mybatis-config로 한다.
- XML 파일을 만들면 위와 같이 한 줄이 적혀있다.
- !DOCTYPE으로 문서 유형을 지정해줘야 한다.
- html 파일은 <!DOCTYPE html>, mapper 파일은 <!DOCTYPE property>를 작성했었다.
- mybatis-configuration은 <!DOCTYPE configuration>을 작성해야 한다.
- 공식 사이트에서 <!DOCTYPE으로 시작하는 3줄을 복붙한다.
- 2번째, 3번째 줄을 보면 dtd가 적혀있다. dtd는 문서 유형에 적법한 요소인지 유효성 체크를 한다.
이 문서 유형에 맞지 않는 태그를 사용하면 빨간줄로 오류를 알려준다.
- 3줄을 연이어서 1줄로 써도 된다.
(1) configurtaion 태그
- 그리고 문서 유형에 맞는 최상위 태그가 필요하다.
- configuration이라는 태그로 감싼다. configuration 태그가 루트 element라는 최상위 태그다.
- 이 태그 안에 다른 태그들을 작성하면 된다.
(2) settings
- 태그명이 복수 형태라는 말은 이 안에 단수 형태로 여러개의 <setting> 태그를 쓸 수 있다는 말이다.
- 자바에서의 null이 db에 들어가려고 하면 마이바티스에서는 오류가 난다.
null로 데이터가 전달되는 경우 DB에서도 null로 인식하게끔 한다.
- 자바에서 null이 전달되면, MyBatis가 그 값을 데이터베이스에서 허용하는 NULL 값으로 인식하도록 한다.
- name 속성값 "jdbcTypeForNull". 대소문자를 잘 구분해야 한다.
- value 속성값 "NULL". 꼭 대문자여야 한다. 아니면 DB 연동 자체가 안 됨.
(3) typeAliases
- dto 클래스를 자주 제시할건데, 그때 클래스를 풀클래스명 대신에 별칭으로 지칭할 수 있도록 별칭을 등록하는 태그.
- 여러개의 <typeAlias> 태그를 쓸 수 있다.
(4) environments
<environments default="development">
<environment id="development">
</environment>
<environment id="production">
</environment>
</environments>
- 여러 개의 <environment> 태그를 쓸 수 있다.
- environments 태그는 연동할 db 정보를 등록하는 태그다.
- 첫번째 environments 태그에는 "개발단에서 사용할 db정보"를,
두번째 environments 태그에는 "운영단에서 사용할 db정보"를 작성한다.
- 각각의 environment 태그를 구분하기 위해서 얘네들을 지칭하는 id를 설정할 수 있다.
보통 개발단에서는 id를 development, 운영단에선 id로 production을 쓰곤 한다.
- 개발 서버와 운영 서버를 다르게 해서 각각 다른 db에 접속하게 할 수 있다.
개발할 때는 위를 쓰고 배포할때는 아래걸 쓰면 된다.
- 배포할 때는 default를 production으로 바꾸면 된다.
지금은 production에 대한 environments는 없어도 되서 지운다. 개발단에서 사용할 db정보만 작성한다.
- 상위 태그인 environments 태그에 default라는 속성에
여러개의 environment 중에서 어떤 id에 해당하는 envirionment와 연결할건지(어떤 db를 쓸건지) 작성할 수 있다.
- default 속성은 연결설정을 여러개 생성해두고 아이디로 구분하는데, 이때 기본적으로 연결시킬 id를 지정한다.
※ envrionment 태그 안에 작성하는 태그들
(i) transactionManager
- type이라는 속성의 값으로 JDBC와 MANAGED를 쓸 수 있다.
- JDBC는 트랜잭션 관리를 개발자가 직접한다. (수동 COMMIT)
항상 수동 COMMIT이 좋다.
- MANAGED는 트랜잭션 관리를 개발자가 직접하지 않는다.
트랜잭션에 대해서 어떠한 영향도 행사하지 않는다. (AUTO COMMIT)
(ii) dataSource
- dataSource에 의해서 Connection 객체가 자동(내부적)으로 생성된다.
- 하위 태그로 property 태그를 둔다. key-value 세트로 driver.properties에 작성했던 내용들을 기술한다.
- driver.properties에 작성할 때는 key값(name 속성값)을 맘대로 했지만
마이바티스는 key값(driver, url, username, password)이 정해져있다.
- dataSource 태그의 type 속성으로 POOLED를 준다.
- POOLED(사용), UNPOOLED(미사용) 중에서 선택할 수 있는데, ConnectionPool 사용 여부를 뜻한다.
- ConnectionPool은 Connection 객체를 담아둘 수 있는 영역이다.
DB에 접속할 때마다 매번 새로운 Connection 객체가 생성했다가 소멸하는 것은 좋지 않다.
한번 생성된 Connection 객체를 ConnectionPool에 담아두면 재사용이 가능하다. 쓰는게 좋다.
(5) mappers 태그
<mappers>
<mapper resource="mappers/notice-mapper.xml" />
<mapper resource="mappers/member-mapper.xml" />
</mappers>
- mappers 태그는 (실행할 sql문들이 기록되어있는) 앞으로 활용할 mapper 파일들을 등록하는 태그다.
- 이렇게 등록해 놓으면 dao측에서 어떤 mapper 파일의 어떤 쿼리를 실행할 건지 쉽게 지칭할 수 있다.
- 여러개의 mapper 파일들을 등록해 놓을 수 있다. namespace 속성값으로 구분한다.
※ mappers 태그에 등록할 mapper 파일 생성하기
- resources.mappers 패키지 안에 notice-mapper.xml과 member-mapper.xml을 만든다.
- 마이바티스 공식 사이트 - "매핑된 SQL 구문 살펴보기"에서 <!DOCTYPE으로 시작하는 3줄을 복사한다.
<?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="noticeMapper">
</mapper>
- notice-mapper.xml과 member-mapper.xml에 저 3줄을 붙여 넣는다.
- dtd로 유효성 체크를 한다.
- 이제부터 쿼리문을 작성하는 문서는 문서 유형을 "mapper"로 한다.
- 최상위 루트 엘리먼트는 mapper다.
- 이전에는 쿼리문을 작성하는 문서 유형이 "properties"였다.
- 최상위 루트 엘리먼트는 properties였고 그 안에 entry 태그를 작성했다.
- 마이바티스에서는 insert, update, select, delete 태그로 다 다르게 작성해야 한다.
- namespace는 MyBatis가 해당 Mapper 파일의 SQL 쿼리를 구분하기 위한 고유한 이름이다.
- 각각의 mapper 파일들마다 무조건 namespace로 각각의 mapper파일을 지칭하는 이름이 등록되어있어야 한다.
- 각각의 mapper 파일들의 mapper 태그의 namespace 속성값을 주지 않고
mybatis-config.xml의 <mappers> 태그에 등록하면 오류난다.
ㅁ 최종 mybatis-config.xml
- mybatis-config.xml 파일에 연결할 db 정보를 작성했다.
MyBatis 설정 파일을 읽어들여서 MyBatis용 객체를 생성하고, 그 객체로 쿼리문을 실행하고 트랜잭션 처리도 진행한다
- JDBCTemplate 클래스에 데이터베이스와 연결된 Connection 객체를 생성하고 반환하는 코드를 작성했었다.
그런식으로 mybatis-config.xml 문서를 읽어들이면서 db와 연결하는 구문을 Template 클래스에 작성한다.
==================================================================================
ㅁ com.br.mybatis.common.template에 Template 클래스를 만든다.
- 마이바티스를 사용하면 JDBC용 객체를 사용할 필요가 없다. 마이바티스에서 내부적으로 다 처리한다.
- 마이바티스용 객체로 SqlSession이라는 객체가 있다.
이 객체 하나로 쿼리 실행, 반납처리, 트랜잭션 처리도 가능하다.
- Template 클래스에는 mybatis용 객체인 SqlSession 객체를 생성해서 반환하는 메소드 하나만 둔다.
mybatis-config.xml 파일을 읽어들여서 해당 db와 접속된 sqlSession 객체를 생성해서 반환하는 코드를 작성한다.
- import문을 보면 java에서 제공하는 클래스가 아니다.
org.apache.ibatis로 시작한다. 마이바티스가 아이바티스에서 넘어왔다.
- mybatis-config.xml을 읽어들이는 자바코드가 위의 3줄이다.
- 읽어들이고자 하는 파일의 일부경로를 가지고 inputStream 객체를 생성하고,
그걸 가지고 SqlSession 관련한 객체를 생성한다.
- 이 코드를 일부 참고해서 작성한다.
- 읽어들이려는 mybatis-config.xml 파일이 소스 폴더 안에 있다.
- mybatis-config.xml 문서를 읽어들이기 위해서는 그 파일과 직접적으로 연결되는 InputStream 객체가 필요하다.
InputStream 객체를 먼저 생성한다.
- Resources 클래스에 읽어들이고자 하는 파일의 일부 경로를 제공하면 그 파일을 쉽게 읽어들일 수 있다.
- Resources.getResourceAsStream() 메소드를 호출하면서 읽어들이고자 하는 파일의 일부 경로를 제시하면 소스 폴더 안에 있는 파일을 읽어들일 수 있다.
지금 resources라는 소스 폴더 안에 config 라는 폴더가 있고, 그 안에 mybatis-config.xml 파일이 있다.
읽어들이고자 하는 파일의 경로를 소스폴더로부터 찾을 수 있게끔 저렇게 일부경로를 제시하면 된다.
- 그러면 내부적으로 이 파일이 찾아지고 그 파일과 직접적으로 연결되는 InputStream 객체가 생성돼서 반환된다.
- SqlSession 객체를 생성하기 위해서는 SqlSessionFactory 객체가 먼저 필요하다.
SqlSessionFactory 객체를 생성하기 위해서는 SqlSessionFactoryBuilder 객체가 필요하다.
좀 복잡한데 굳이 알 필요는 없다. 저 3줄을 가지고 참고해서 쓰면 된다.
- SqlSessionFactoryBuilder 객체가 제공하는 build() 메소드를 호출하면서 InputStream 객체를 전달하면 SqlSessionFactory 객체를 반환한다.
- 반환받은 SqlSessionFactory 객체로부터 openSession이라는 메소드를 호출하면 SqlSession 객체를 반환받을 수 있다.
- openSession 메소드 호출시 false를 전달하면 auto commit을 안하겠다는 의미이다. 여기서도 써줘야 한다.
ㅁ 다시 main.jsp로 돌아온다.
- main.jsp를 건들진 않고 확인만 함.
- 기능별로 서비스측에 어떤 메소드가 만들어져야 할지 미리 설계한다.
- 기능 분석이 끝났으면 그 기능을 처리하기 위해 서비스측에 어떤 메소드가 필요할지 예측이 가능해야 한다.
(매개변수, 반환형 등)
ㅁ com.br.mybatis.notice.service 패키지에 NoticeService라는 인터페이스를 만든다.
- 그런데 서비스 클래스를 바로 만들지 않고 인터페이스를 만든다.
- 인터페이스도 클래스다. 단지 추상 메소드만 존재할 수 있는 클래스다.
- 인터페이스의 모든 메소드들에는 묵시적으로 public abstract가 붙는다.
ㅁ com.br.mybatis.notice.service에 NoticeServiceImpl 클래스를 만든다.
- 인터페이스 구현 클래스를 만들 때, 'Add'를 눌러서 인터페이스를 검색하고 선택해서 implements된 채로 만들 수 있다.
- 인터페이스를 구현해서 미완성된 메소드들이 오버라이딩되어 있다. 반환형, 매개변수, 메소드명은 다 정해져있다.
- 각 기능에 맞게 서비스측 코드를 메소드 안에 채워 넣기만 하면 된다.
ㅁ com.br.mybatis.notice.dao에 NoticeDao를 만든다.
ㅁ main.jsp 수정
- a 태그로 공지사항 등록 페이지로 이동하게끔 한다.
그런데 이제 WEB-INF 폴더 안의 views폴더에 둔 페이지들은 무조건 서블릿을 통해서만 페이지 이동이 가능하다.
ㅁ com.br.mybatis.notice.controller에 NoticeRegistFormController를 만든다.
- 어노테이션을 /regist.no로 변경한다.
- 단순히 공지사항 등록페이지로 이동만 하는 서블릿이다.
ㅁ noticeRegistForm.jsp를 만든다.
- DB의 NOTICE 테이블을 보면 INSERT할 때 NOTICE_WRITER 컬럼(공지사항 글 작성자 번호)가 필요한데, 로그인 되어있다고 치고 1번회원이라고 가정한다. (현재 이 프로젝트에 로그인 기능이 구현되어 있지 않음)
ㅁ com.br.mybatis.notice.controller에 NoticeInsertController라는 서블릿을 만든다.
ㅁ NoticeServiceImpl를 수정한다.
- 잘 생각해보면 insert에 실패하면 들어간 데이터가 없기 때문에 rollback할 필요가 없다.
=====================================================================================
ㅁ 쿼리
- 마이바티스에서는 insert, update, select, delete 각각의 쿼리에 맞는 태그를 사용해야 한다.
- 각 태그에 id, parameterType, resultType, resultMap 4가지 주요 속성이 있다.
- sql문 실행시, 해당 sql문으로 전달되는 parameter로 부터 값을 뽑아서 채우고자 한다면 #{ } 또는 ${ }를 사용한다.
(1) id : 해당 sql문의 식별자 (dao측에서 실행할 sql문을 탐색할 때 사용됨)
- ex) dao에서 "mapper파일의 namespace"."sql문의 id"를 제시해서 sql문 실행한다.
(2) parameterType : 해당 sql문으로 전달되는 파라미터의 타입 (생략가능)
- ex) parameterType="com.br.mybatis.notice.dto.NoticeDto" - 기본적으로 풀클래스명을 써야 함.
- ex) parameterType="NoticeDto" - alias를 등록한 경우에는 풀클래스명을 안 써도 됨.
- 전달된 파라미터가 내가 만든 dto 객체가 아니라 자바 기본 자료형일 수도 있다.
- ex) parameterType="_int" <- mybatis 내장 별칭 (int가 전달되어도 _int라고 써야 함)
- ex) parameterType="string" <- mybatis 내장 별칭 (String이 전달되어도 string이라고 써야 함)
- ex) parameterType="map" <- mybatis 내장 별칭이 정해져 있다.
- 엄청 많은데 어차피 생략가능하다.
(3) resultType
- select문에 작성하는 속성으로 반환값의 타입을 명시.
- insert, update, delete는 어차피 int 반환만 하기 때문에 반환값의 타입을 명시할 필요가 없다.
(4) resultMap
- db의 컬럼명과 담고자하는 dto 객체의 필드명을 따로 작성해서 매핑되도록 하는 태그.
※ 쿼리문의 실행 결과
- insert, update, delete는 처리 결과가 무조건 처리된 행 수인 int로 고정이다.
- select는 매번 결과에 대한 타입이 다르다.
count(*) 집계함수를 사용해서 처리된 행 수 하나만 조회될 수도 있다.
- ex) 조회된 값이 숫자 한개일 경우 자바의 int형으로 바로 반환하고 싶을 때 resultType="_int"
- ex) 조회된 값이 문자열 한개일 경우 자바의 String형으로 바로 반환하고 싶을때 resultType="string"
- ex) 조회된 한 행을 특정 dto 객체의 각 필드에 매핑해서 반환하고자 할 때
(단, 조회되는 컬럼들의 컬럼명이 담고자하는 dto객체의 필드명과 일치)
resultType="dto객체의타입"
- 마이바티스 공식 사이트 - 매퍼설정의 typeAliases 부분에서 MyBatis 내장 별칭들을 볼 수 있다.
※ sql문에서 전달된 parameter로 값을 설정하는 방법
(1) # { }
- 내부적으로 ?와 같은 역할을 수행한다. pstmt 방식으로 값을 처리한다.
- #{ 전달된 dto객체의 필드 | 전달된 Map의 key | 전달된 변수명 }을 작성하면 값들이 꺼내진다.
- #{ }이 해당 값의 타입에 맞춰서 대체된다. (해당 값의 타입에 맞춰서 오라클에 반영된다)
문자열이면 오라클에서의 문자열인 홑따옴표로 감싸진 채로 출력되고, 숫자면 따옴표 없이 그냥 출력된다.
- ex) 전달된 dto객체의 name필드에 "홍길동", int age 필드에 10이라는 가정하에
where user_name = #{ name } and user_age = #{ age } => where user_name = '홍길동' and user_age = 10
// pstmt.setString(1, name); pstmt.setInt(2, age); 과 같다.
(2) $ { }
- 값이 따옴표 없이 그대로 채워진다. 즉 문자열 데이터로 인식되지 않는다.
- ${ }는 PreparedStatement를 사용하지 않는다.
?로 처리되지 않으며, 값이 SQL 쿼리문 안에 직접 삽입된다.
- sql문의 메타데이터(테이블명, 컬럼명, sql 자체 등)를 처리할 때 사용한다.
쿼리문 작성할 때 메타데이터(테이블 명이나 키워드, 컬럼명)에는 따옴표를 쓰지 않는다.
메타데이터들을 채울 때 ${ }를 사용한다.
- 따옴표나 이스케이프 문자없이 그대로 출력된다.
- ex) 전달된 변수 String table에 "member"라는 문자열 데이터가 있었을 경우
select * from ${ table } => select * from member
====================================================================================
ㅁ notice-mapper.xml을 수정한다.
- insert 태그의 id를 메소드명과 동일하게 작성했다.
- 사실 parameterType 속성은 없어도 실행이 잘 된다. 옛날에는 필수였겠지만 지금은 옵션이다.
- #{ noticeTitle }이 pstmt.setString(1, n.getNoticeTitle());이다.
- #{ noticeContent }이 pstmt.setString(2, n.getNoticeContent());이다.
- #{ noticeWriter }이 pstmt.setString(3, n.getNoticeWriter());이다.
- 이제부터 sql문 작성할 때 물음표를 쓰지 않는다.
물음표를 채우기 위한 객체를 전달받고, 어떤 필드값을 꺼낼건지를 애초에 작성할 예정이다.
ㅁ NoticeDao를 수정한다.
- 길었던 dao의 코드가 1줄로 줄어들었다.
- 이제부터 sql문을 작성할 때 물음표를 사용하지 않는다.
- select는 한 행 조회면 selectOne 메소드, 여러행 조회면 selectList 메소드가 있다.
selectList 메소드는 3종류가 있다. (완성된 sql문, 미완성된 sql문, 페이징처리 RowBounds rowBounds)
- insert, update, delete 메소드는 매개변수 하나짜리 메소드와 매개변수 두개짜리 메소드가 있다.
- 이미 완성된 sql문이면 n을 전달할 필요가 없다. 그냥 매개변수 하나짜리 insert 메소드를 사용하면 된다.
- 완성되지 않은 sql문이면 두번째 인자값으로 Object parameter를 전달한다.
- insert, update, delete 메소드들은 두 종류의 메소드 다 int를 반환한다. 그 int를 리턴한다.
- 첫번째 인자값으로는 현재 등록되어있는 매퍼 파일들 중에서 어떤 매퍼파일의 어떤 id를 가진 sql문을 실행할 건지 쓴다.
ㅁ insert 기능 사용해보기
- 제목과 내용을 작성하고 등록하기를 누른다.
- 메인페이지로 돌아온다.
- 콘솔에도 뜨고 db에도 insert가 되었다.
============================================================================
[ 연습 update ]
ㅁ notice-mapper.xml에 id가 updateNotice인 update 태그를 만든다.
- 사실 parameterType은 없어도 된다. 나중엔 생략할 예정이다.
ㅁ NoticeDao에 updateNotice()를 만든다.
ㅁ dao와 쿼리문만 연습차원에서 하나씩 더 써봤다.
===================================================================================
[ 연습 delete ]
- 글번호 int를 받는다. parameterType의 속성값은 "_int"다. 생략 가능.
- 마이바티스에서는 int라고 쓸수 없고 _int라고 써야한다. 물론 parameterType 속성 자체를 안써도 된다.
- #{ }에 변수명을 쓰면 변수에 담겨진 값이 알아서 꺼내진다.
'MyBatis' 카테고리의 다른 글
[MyBatis] select + update 연습 (TypeHandler 적용) (2) | 2024.10.11 |
---|---|
[MyBatis] select (3) 여러행 + 페이징 처리 (RowBounds 적용) (0) | 2024.10.11 |
[MyBatis] select (2) 여러 행 조회 (0) | 2024.10.11 |
[MyBatis] select (1) 한 행 조회 (0) | 2024.10.11 |
[MyBatis] 소개, MyBatis 세팅(1/2) (4) | 2024.10.10 |