2020-11-11 TIL
MyBatis
도입
Data Persistence Framework => 데이터의 영속성(지속성; 등록,조회,변경,삭제)을 대신 처리해주는 프레임워크. 1) SQL Mapper
- 직접 SQL 문을 작성
- 각각의 DBMS에 최적화된 SQL을 작성할 수 있다.
- DBMS마다 미미하게 다른 SQL을 작성해야 하는 번거로움이 있다.
- 예) Mybatis 등 2) OR Mapper
- 전용언어 및 문법(Domain-Specific Language;DSL)을 사용하여 작성 실행할 때 DBMS에 맞춰서 SQL을 생성하여 실행한다.
- DBMS에 마다 SQL문을 작성할 필요가 없어 편리하다.
- DBMS에 최적화된 SQL을 실행할 수 없다. 즉 DBMS의 특징을 최대로 활용할 수 없다.
- 예) Hibernate, TopLink 등
Mybatis 도입 1) 의존 라이브러리 추가
- mvnrepository.com 검색하여 build.gradle 파일에 추가한다.
- “gradle eclipse” 실행한 후 이클립스 에디터에서 프로젝트를 “refresh” 한다. 2) mybatis 설정 파일 준비
- mybatis-config.xml 생성 및 편집 3) DB 연결 정보를 담은 프로퍼티 파일 준비
- jdbc.properties 생성 및 편집 4) SQL 문장을 작성할 파일 준비
- BoardMapper.xml 생성 및 편집 5) Mybatis 객체 준비
<?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>
<!-- jdbc.properties 파일의 내용을 읽어온다.
읽어온 정보는 ${프로퍼티명} 문법을 이용하여 그 값을 사용할 수 있다. -->
<properties resource="com/eomcs/mybatis/ex01/jdbc.properties"></properties>
<!-- DBMS에 연결할 때 사용할 정보를 설정한다.
여러 개의 연결 정보를 설정해두고 그 중에 사용할 정보를 지정할 수 있다.
default="development"의 의미는,
여러 연결 정보 중에서 "development"라는 연결 정보를 사용하여 실행하겠다는 의미다. -->
<environments default="development">
<!-- 각각의 연결 정보는 다음과 같이 environment 태그에 설정한다. -->
<environment id="development">
<!-- 트랜잭션 관리 방식을 지정한다. -->
<transactionManager type="JDBC"/>
<!-- DB 커넥션 풀에 관련된 정보와 DB 연결 정보를 설정한다.
이제 개발자가 DB 커넥션 풀을 다룰 필요가 없다.
mybatis 프레임워크에서 관리한다. -->
<dataSource type="POOLED">
<!-- ${위의 .properties 파일에 저장된 프로퍼티명} -->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- SQL문을 모아둔 파일(SQL 맵퍼 파일이라 부른다)을 지정한다.
SQL 맵퍼 파일에 작성해 둔 SQL문을 mybatis가 사용할 것이다. -->
<mappers>
<!-- 맵퍼 파일의 경로를 지정할 때 classpath 경로를 사용해야 한다.
단 패키지명을 구분할 때 '.' 대신에 '/'를 사용해야 한다. -->
<mapper resource="com/eomcs/mybatis/ex01/BoardMapper.xml"/>
</mappers>
</configuration>
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
// 1) 직접 파일 시스템 경로를 지정하기
// => 단 소스 파일 경로를 지정하지 말아라.
// => 컴파일된 후 XML 파일이 놓이는 경로를 지정해라.
// => 자바 패키지에 작성한 일반 파일은 그대로 빌드 디렉토리에 복사된다.
// => 예) 프로젝트폴더/bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml
//
InputStream mybatisConfigInputStream = new FileInputStream(//
"./bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml");
// 2. SqlSessionFactory를 만들어 줄 빌더 객체 준비
//
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
// 3. SqlSession 객체를 만들어 줄 팩토리 객체 준비
// => mybatis는 Builder를 이용하여 SqlSessionFactory 객체를 만든다.
// => 이때 공장 객체를 만들 때 사용할 설정 파일을 지정한다.
// => 설정 파일의 경로를 직접 지정하지 말고,
// 해당 파일을 읽을 때 사용할 InputStream을 넘겨줘라.
//
SqlSessionFactory factory = factoryBuilder.build(mybatisConfigInputStream);
// 4. SQL을 실행시키는 객체 준비
// => SqlSessionFactory 객체로부터 SqlSession 객체를 얻는다.
// => openSession()은 수동 커밋으로 SQL을 다루는 객체를 리턴한다.
// => 자동 커밋으로 SQL을 다루고 싶다면,
// openSession(boolean autoCommit) 메서드를 호출하라.
//
SqlSession sqlSession = factory.openSession();
System.out.println("mybatis 준비 완료!");
sqlSession.close();
}
}
public static void main(String[] args) throws Exception {
// 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
// => 다음과 같이 mybatis 설정 파일의 경로를 직접 지정하면
// 애플리케이션 배포 경로가 바뀔 때 마다
// 소스를 변경하고 다시 컴파일 해야 하는 문제가 있다.
// InputStream mybatisConfigInputStream = new FileInputStream(//
// "./bin/main/com/eomcs/mybatis/ex01/mybatis-config.xml");
// => 이를 간편하게 하기 위해 Mybatis는 도우미 객체를 제공한다.
// => Resources 클래스의 메서드를 이용하면
// 자바 클래스가 있는 패키지 폴더에서 mybatis 설정 파일을 찾을 수 있다.
//
InputStream mybatisConfigInputStream = Resources.getResourceAsStream(//
"com/eomcs/mybatis/ex01/mybatis-config.xml");
// => 파라미터에 mybatis 설정 파일의 경로를 지정할 때,
// 자바 패키지 경로를 그대로 이용한다.
// => 단 파일 경로이기 때문에 폴더와 폴더 사이를 가리킬 때
// . 대신에 / 를 사용해야 한다.
// => JVM은 현재 실행하는 애플리케이션의 자바 클래스 경로를 알고 있다.
// => 주의!
// 자바 패키지 경로에서 찾기 때문에 mybatis 설정 파일은 반드시
// 자바 패키지 경로에 있어야 하다.
//
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = factoryBuilder.build(mybatisConfigInputStream);
SqlSession sqlSession = factory.openSession();
System.out.println("mybatis 준비 완료!");
sqlSession.close();
}
}
public static void main(String[] args) throws Exception {
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(//
Resources.getResourceAsStream(//
"com/eomcs/mybatis/ex01/mybatis-config.xml"));
SqlSession sqlSession = factory.openSession();
// SqlSession 객체를 이용하여 SQL 맵퍼 파일에 작성한 SQL 문을 실행한다.
// => select 문장
// - sqlSession.selectList() : 목록 리턴
// - sqlSession.selectOne() : 한 개의 결과 리턴
// => insert 문장
// - sqlSession.insert()
// => update 문장
// - sqlSession.update()
// => delete 문장
// - sqlSession.delete()
// => insert/update/delete인 경우 insert()/update()/delete() 메서드 중
// 아무거나 호출해도 된다.
// 하지만 일관된 유지보수를 위해 메서드를 구분하여 사용하라!
//
// 메서드 사용법)
// => 예) selectList(SQL문 식별자, 파라미터값)
// - SQL문 식별자 = 그룹명 + "." + SQL문장 아이디
// - 그룹명: <mapper namespace="그룹명">...</mapper>
// - SQL 문장 아이디: <select id="SQL문장 아이디">...</select>
// - 파라미터 값: primitive type 및 모든 자바 객체가 가능하다.
// 여러 개의 값을 전달할 때는 Map에 담아 넘겨라!
List<Board> list =
sqlSession.selectList("BoardMapper.selectBoard");
for (Board board : list) {
System.out.printf("%d, %s, %s, %s, %d\n",
board.getNo(),
board.getTitle(),
board.getContent(),
board.getRegisteredDate(),
board.getViewCount());
}
sqlSession.close();
}
}
// selectList() 동작 원리
// ---------------------------------------------------------------------
// <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.Board">
// select
// board_id,
// title,
// contents,
// created_date,
// view_count
// from x_board
// </select>
//---------------------------------------------------------------------
// => resultType 에 지정한 클래스의 인스턴스를 생성한다.
// => 컬럼 이름과 일치하는 프로퍼티를 찾아 값을 입력한다.
// board_id --> setBoard_id(컬럼값)
// title --> setTitle(컬럼값)
// contents --> setContents(컬럼값)
// created_date --> setCreated_date(컬럼값)
// view_count --> setView_count(컬럼값)
// => 컬럼 이름과 일치하는 프로퍼티(setter)가 없다면
// 그 컬럼의 값은 객체에 담을 수 없다.
// => 이 예제에서 컬럼 이름과 일치하는 프로퍼티는 title 밖에 없다.
//
public static void main(String[] args) throws Exception {
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(//
Resources.getResourceAsStream(//
"com/eomcs/mybatis/ex01/mybatis-config.xml"));
SqlSession sqlSession = factory.openSession();
List<Board> list = sqlSession.selectList("BoardMapper.selectBoard2");
for (Board board : list) {
System.out.printf("%d, %s, %s, %s, %d\n", board.getNo(), board.getTitle(), board.getContent(),
board.getRegisteredDate(), board.getViewCount());
}
sqlSession.close();
}
}
// 컬럼 이름과 자바 객체의 프로퍼티 이름을 같게 하기
// ---------------------------------------------------------------------
// <select id="selectBoard" resultType="com.eomcs.mybatis.ex01.Board">
// select
// board_id as no,
// title,
// contents as content,
// created_date as registeredDate,
// view_count as viewCount
// from x_board
// </select>
// ---------------------------------------------------------------------
// => 컬럼의 값을 자바 객체에 담으려면 컬럼과 같은 이름의 프로퍼티가 있어야 한다.
// => 없다면 위와 같이 프로퍼티 명을 컬럼의 별명으로 지정하라.
//
// mybatis 설정 파일에서 fully-qualified class name 을 사용하는 대신에
// 짧은 이름으로 대체할 수 있다.
// <typeAliases>
// <typeAlias type="com.eomcs.mybatis.ex01.Board" alias="abc"/>
// </typeAliases>
//
// 그러면 이 별명을 어디에 사용하는가?
// => SQL 맵퍼 파일에서 클래스를 지정할 때 사용한다.
// <select id="selectBoard2" resultType="abc">
// select
// board_id as no,
// title,
// contents as content,
// created_date registeredDate,
// view_count viewCount
// from x_board
// </select>
//
// 참고
//
public class Exam0210 {
public static void main(String[] args) throws Exception {
InputStream inputStream = Resources.getResourceAsStream( //
"com/eomcs/mybatis/ex01/mybatis-config02.xml");
SqlSessionFactory factory = //
new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();
List<Board> list = sqlSession.selectList("BoardMapper.selectBoard");
for (Board board : list) {
System.out.printf("%d, %s, %s, %s, %d\n", //
board.getNo(), //
board.getTitle(), //
board.getContent(), //
board.getRegisteredDate(), //
board.getViewCount());
}
sqlSession.close();
}
}
<!-- mybatis 설정 파일을 작성할 때,
자식 태그의 순서를 지켜야 한다.
=> mybatis 설정 파일 작성 규칙에 순서를 지키도록 정의되어 있다.
-->
<properties resource="com/eomcs/mybatis/ex01/jdbc.properties"></properties>
<!-- 긴 이름의 클래스명을 사용하는 대신에 짧은 이름의 별명을 사용해보자! -->
<typeAliases>
<!-- 주의!
패키지를 포함한 클래스 이름은 항상 . 으로 표기해야 한다.
/ 는 파일 경로를 가리킬 때 사용한다.
-->
<typeAlias type="com.eomcs.mybatis.ex01.Board" alias="Board"/>
</typeAliases>
컬럼과 프로퍼티
-
SQL문은 태그 안에 작성한다.
-
select 태그 id : SQL문을 찾을 때 사용할 식별자이다. resultType : select 결과를 저장할 클래스이름이나 별명이다. 클래스이름을 경우 반드시 fully-qualified class name(패키지명을 포함한 클래스명)을 사용하라!
-
값을 자바 객체에 넣는 규칙: => 컬럼명과 일치하는 셋터를 호출한다. 컬럼명 ==> set컬럼명() => 예) bno ==> setBno(값) 즉, Board board = new Board(); board.setBno(rs.getNo(“bno”)); 만약 컬럼 이름에 해당하는 셋터를 못 찾으면 호출하지 않는다.
-
거울처럼 클래스 안에 있는 메서드를 알려주는 것들을 리플렉션 API라고 한다.
-
xml 문법 // &lessthan = < 를 의미한다. // 태그 안에 주석을 달면 안된다.
select board_id, title, contents, created_date, view_count from x_board where board_id < #{ohora} </select>
// xml 파서에게 전부 문자라고 알려준다. // 이게 없으면 파서는 < 를 태그 시작점이라고 생각한다.
페이징 처리
- 오라클 https://m.blog.naver.com/wideeyed/221796538283
- mysql https://ggmouse.tistory.com/198
sql 파라미터 지정하기
- ${} 는 sql 삽입 공격을 당할 수 있기 때문에 사용하지 않는다.
- 입력이 아니라 선택받는 것으로 한다면 활용할 수 있다.
dynamic sql - 조건문
if 조건문
- 조건에 따라 생성할 SQL문을 제어할 수 있다.
- 문법 :
SQL문 - 예 :
- 여기서 no 는 파라미터 타입이 프리머티브 타입인 경우 마음대로 적을 수 있다.
- 하지만 그 외의 타입은 정확하게 이름을 적어야 한다.
- 문법 :
- ”%” + keyword + “%” : keyword 가 포함된 것 전부 검색
- ”%” + keyword : keyword 가 앞에 붙어있는 것 검색
where 절 사용
-
where 태그를 사용하면 or/and 앞에 아무것도 없을 때 or/and 를 자동으로 제거한다.
or board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%') </select>
board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%') </select>
trim 사용
-
or/and 자동 제거
board_id = #{no} or title like concat('%', #{title}, '%') or contents like concat('%', #{content}, '%') </select>