20.12.21~24 주제
Mybatis
hibernate validator
EL
custom Tag
회원관리_JDBC
MemberListController
MemberDAOImpl_JDBC.java
개발전에 다이어그램을 먼저 그려보세요
페이징
주요 데이터 요소
- totalRecord : 총 게시물 수
- screenSize : 한 페이지당 리스트 수
- 임의의 값. 개발자/디자이너가 결정
- ex. 10개
- totalPage : 총페이지 수
- (totalRecord+(screenSize-1))/screenSize
- ex. (100+(10-1))/10 = 10
- currentPage : 현재 페이지
- 클라이언트가 결정. 없으면 1로 셋팅
- ex. 8번
- endRow : 한 페이지에서 종료 게시물
- screenSize * currentPage
- ex. 10 * 8 = 80
- startRow : 한 페이지에서 시작 게시물
- endRow - (screenSize - 1)
- 80 - (10-1) = 71
- blockSize : 한 화면에 보여줄 페이지 수
- 임의의 값. 개발자/디자이너가 결정.
- ex. 5개 페이지/1블럭
- startPage : 한 블럭의 시작페이지
- ((currentPage - 1) / blockSize) * blockSize
- ex. ((8-1)/5) * 5 = 6
- endPage : 한 블럭의 마지막페이지
- startPage + (blockSize -1)
- ex. 6 + (5-1) = 10
totalRecord
- 아래 쿼리는 망한 쿼리
- 왜 ?
- rownum은 의사컬럼 : 실시간으로 동적으로 만들어지는 컬럼. 쿼리 실행순서(from-where-select)에 의해 데이터 조회되지 않음 (아직 만들어지지 않은 데이터를 사용하는 격)
- 의사컬럼을 미리 존재하는 컬럼으로 만들어서 조회
- 정렬을 위해 한번 더 인라인 뷰 사용함
- 쿼리 실행 순서 : 7-6-8-5-4-2-11-12-1
- FROM - WHERE - GROUP BY - HAVING - SELECT - ORDER BY
- SELECT 보다 늦게 실행되는 것은 ORDER BY 뿐 !
- SELECT 절의 Alias 는 ORDER BY 절에서만 사용가능.
- https://data-make.tistory.com/23
myBatis
- Persistance 레이어와 DB사이에서 동작하는 프렘임웍.
- SQL mapper = ORM = DM 이라고 부르기도 함
- 이름의 의미를 생각해보면 어떤 역할을 하는지 알 수 있음.
DataMapper | SQL Mapper | DataMapper
- JDBC 드라이버 로딩부터 클로즈까지 6단계 과정이 똑같이 이루어지는데, 직접하지 않고 프레임웍이 해줌
- IoC / DI 패턴 : 제어 반전, 역제어. 프로그래머가 작성한 프로그램이 재사용 라이브러리의 흐름 제어를 받게 되는 소프트웨어 디자인 패턴(의존관계 역전패턴)
회원관리_myBatis
myBatis는
- iBatis가 버전업된 것
- 클래스패스 리소스 형태로 클래스로드를 통해 접근
- iBatis나 myBatis나 내부적으로는 jdbc 프로그래밍.
jdbc 프로그래밍 6단계
- 드라이버로딩
- connection 생성
- query 객체 생성
- query 실행
- ResultSet 활용
- close
시작하기
maven dependency 추가
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Configuration.xml
- xml로 만들기 -> DTD 파일
- Configuration.xml
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
- environments : 여러개의 environment를 가질 수 있음
- environment : 트랜잭션 관리와 커넥션 풀링을 위한 환경설정
- POOLED : DB 커넥션 풀링
커넥션풀 ?
- 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 있다가 필요할 때에 커넥션을 풀에서 가져다 쓰고 다시 풀에 반환하는 기법
- 특징
- 풀 속에 미리 커넥션이 생성되어 있기 때문에 커넥션을 생성하는데 드는 연결 시간이 소비되지 않음
- 커넥션을 계속 재사용하기 때문에 생성되는 커넥션 수가 많지 않음
- mappers : SQL 코드와 매핑 정의를 가지는 mapper.xml 파일 목록 지정
SqlSessionFactory 빌드하기
- 데이터베이스에서 session은 통로의 의미
- iBatis : sqlMapClient
- myBatis : sqlSession
- Configuration.xml 파일을 이용한 SqlSessionFactory build
- mapper.xml 파일은 configuration.xml에 따라옴
-- Class CustomSqlSessionFactoryBuilder--
(싱글톤으로 SqlSessionFactory 빌드)
private static SqlSessionFactory sqlSessionFactory;
static{
String resource = "configuration.xml 의 qualified name"
try(
Reader reader = Resource.getResourceAsReader(resource);
){
sqlSessionFactory = new SqlSessionFactoryBuilder().builde(reader);
}catch(IOException e){
throw new RuntimeException(e);
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
-- Class DAOImpl--
private SqlSessionFactory sqlsessionFactory = CustomSqlSessionFactoryBuilder.getSqlSessionFactory();
mapper.xml
- 전자정부 이클립스에는 이미 myBatis 플러그인이 있음
- 매핑파일 만들때 사용
- myBatis는 namespace 필수 ! (ibatis와 차이)
- namespace 없으면 마이바티스 구조완성이 안됨
- namespace 로 DAO의 qualified name을 가짐
- 마이바티스 내부에서 리플렉션 작업 이루어짐
- DAO의 인터페이스가 어떤 메소드를 가지고 있는지 알게됨.
- 메소드 : 쿼리 = 1 : 1
- 후에 매퍼프록시가 만들어져야 하는데, namespace가 이상하면 못만듦.
- 프록시가 만들어지지 않으면 myBatis는 못쓴다고 봐도 ..
- myBatis는 typeAlias를 mapper.xml에 만들 수 없음.
- 모든 xml 에서 사용하기 위해 configuration.xml에 만듦
<typeAliases>
<package name="패키지">
<typeAlias name="클래스">
</typeAliases>
- 자기 클래스 이름으로 알리아스 잡힘
- 그래서 qualified name 사용 (아마두?!)
- 쿼리
- 크게 select 계열과 update 계열로 나뮈
- 그래서 < delete > 태그 안에서 update 쿼리 사용할 수 있음
- 인라인파라미터
- iBatis : #인라인파라미터#
- 마이바티스 #{인라인파라미터}
- Null 값
- iBatis에서는 null↔"" 서로 변환되어 들어가는데 myBatis는 안됨 => NULL 처리 필요
- Null을 어떤 타입에 맞춰서 넣을 건지 결정
- jdbcType의 enum 사용
DAOImpl
- 옛날방식
- sqlSession.selectOne("DAO의 qualified name.method", parameter)
- = queryForObject... insert, update, delete ...
- 오타때문에 타입안정성이 없음
- 요즘방식 : Mapper Proxy
- sqlSession.getMapper(IMemberDAO.class);
- 위 인터페이스의 퀄러파이드네임에 해당하는 네임스페이스를 찾음
Mapper (쿼리)
OGNL 표기법
- Object Graph Navigation Language
- 일종의 표현언어
- 내부적으로 스크립트언어 형태
- MyBatis 는 XML element를 줄이고 다양한 조건을 처리하기 위해 OGNL 표현식을 사용
- 동적SQL 처리를 지원하기 위해 지정된 엘리먼트들 제공함
- if, choose(when, otherwise), trim(where, set), foreach ...
- static method 호출 방법 : @class@method(argd)
- ex. StringUtils의 isNotBlank 사용하기
- @org.apache.commons.lang3.StringUtils@isNotBlank(searchVO.searchWord))
- iBatis의 다이나믹 엘리먼트 대신 myBatis에서는 OGNL을 다양하게 활용
< ![CDATA][] >
- 태그 안에서 < 가 일반 문자로 인식되게 함
마이페이지
- 요구사항 변경 ! 우리 클라이언트는 마이페이지에서 구매한 상품 목록이 보고 싶어짐
- 기존 VO를 활용해서 2개 이상의 테이블을 조인했을 때 어떻게 가져올까 ?
selectMember
- 1.도메인 레이어를 각각 따로 만들기
- 2.모델링
- 데이터들의 관계 파악 : has a(1:1), has many(1:n)
- ex. member와 prod는 1:n 관계 : member has many prod
ex. prod와 buyer는 1:1 관계 : prod has a buyer
- VO와 VO 사이에 반영해주기
- MemberVO 에 포함된 ProdList
- ProdVO에 포함된 BuyerVO
- resultType을 이용한 자동바인딩이 불가해짐 -> 수동바인딩 : resultMap
- 수동으로 하던 자동으로 하던 반환타입은 memberVO여야됨.
- autoMapping = true : 규칙성에 따라 자동바인딩
- 식별성 여부에 따라
- id : 식별성이 있는 녀석 바인딩. mem_id가 같으면 더 이상 memberVO를 만들지 않음
→ 반환값은 memberVO 인데 중복제거 되지 않은 상태라 '너무많은데이터' 에러가 뜬 것
- result : 식별성이 없는 녀석 바인딩할 때 사용
- 1:1, 1:n 관계의 바인딩구조가 다름
- collection : has many
- association : has a
미션