개발자입니다
[JDBC] 예제 소스 정리 - Mybatis 본문
[JDBC] 예제 소스 정리 - Mybatis
끈기JK 2023. 2. 16. 08:35com.eomcs.mybatis
예제 소스 정리
package com.eomcs.mybatis.ex01
Data Persistence Framework 도입 - 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) Mybatis 라이브러리 파일을 프로젝트에 등록하기
- mvnrepository.com 또는 search.maven.org에서 mybatis를 검색하여 라이브러리 정보 알아낸다.
- build.gradle 파일에 의존 라이브러리 정보를 추가한다.
- 'gradle eclipse' 실행하여 라이브러리를 다운로드 받고, 이클립스 설정 파일에 등록한다.
- 이클립스 프로젝트를 리프래시하여 변경된 설정 파일의 정보를 반영한다.
2) Mybatis 설정 파일 준비
- mybatis.org 사이트에서 문서 페이지를 참조한다.
- Mybatis 설정 파일(예: mybatis-config.xml)을 생성한다.
- 문서 페이지를 참조하여 설정 파일의 내용을 변경한다.
package com.eomcs.mybatis.ex01.a;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
// 1) 직접 파일 시스템 경로를 지정하기
// => 단 소스 파일 경로를 지정하지 말아라.
// => 컴파일된 후 XML 파일이 놓이는 경로를 지정해라.
// => 자바 패키지에 작성한 일반 파일은 그대로 빌드 디렉토리에 복사된다.
// => 예) 프로젝트폴더/bin/main/com/eomcs/mybatis/ex01/a/mybatis-config.xml
//
InputStream mybatisConfigInputStream = new FileInputStream(
"./bin/main/com/eomcs/mybatis/ex01/a/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();
}
}
ex01/a/mybatis-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>
<!-- DBMS에 대한 정보를 설정한다.
default 속성 : SQL을 실행할 때 연결할 DBMS 연결 정보의 ID
-->
<environments default="development">
<!-- DBMS의 연결 정보는 다음과 같이 environment 태그에 설정한다. -->
<!-- 예) 개발용 DBMS -->
<environment id="development">
<!-- 트랜잭션 관리 방식을 지정한다. -->
<transactionManager type="JDBC"/>
<!-- DB 커넥션 풀에 관련된 정보와 DB 연결 정보를 설정한다.-->
<dataSource type="POOLED">
<property name="driver" value="org.mariadb.jdbc.Driver"/>
<property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
<property name="username" value="study"/>
<property name="password" value="1111"/>
</dataSource>
</environment>
<!-- 예) 테스트용 DBMS -->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.mybatis.jdbc.Driver"/>
<property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
<property name="username" value="study"/>
<property name="password" value="1111"/>
</dataSource>
</environment>
<!-- 예) 실무에서 운용할 때 사용할 DBMS -->
<environment id="operation">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.mybatis.jdbc.Driver"/>
<property name="url" value="jdbc:mariadb://localhost:3306/studydb"/>
<property name="username" value="study"/>
<property name="password" value="1111"/>
</dataSource>
</environment>
</environments>
</configuration>
Data Persistence Framework 도입 - 좀 더 쉽게 Mybatis 설정 파일의 InputStream 얻는 방법
package com.eomcs.mybatis.ex01.a;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0120 {
public static void main(String[] args) throws Exception {
// 1. mybatis 설정 파일을 읽을 InputStream 도구를 준비한다.
// => 다음과 같이 mybatis 설정 파일이 있는 경로를 직접 지정하면
// 애플리케이션의 배포 경로가 바뀔 때 마다 파일 경로를 바꾸기 위해
// 소스를 변경하고 다시 컴파일 해야 하는 문제가 있다.
// InputStream mybatisConfigInputStream = new FileInputStream(
// "./bin/main/com/eomcs/mybatis/ex01/a/mybatis-config.xml");
// => 이런 문제를 해결하기 위해 Mybatis는 도우미 객체를 제공한다.
// => Resources 클래스의 메서드를 이용하면
// 자바 클래스가 있는 패키지 폴더의 mybatis 설정 파일을 바로 지정할 수 있다.
//
InputStream mybatisConfigInputStream = Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/a/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();
}
}
Data Persistence Framework 도입 - 코드 정리!
package com.eomcs.mybatis.ex01.a;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0130 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/a/mybatis-config.xml")).openSession();
System.out.println("mybatis 사용 준비 완료!");
sqlSession.close();
}
}
Mybatis 설정 파일 - DBMS 연결 정보를 .properties 파일로 분리하기
package com.eomcs.mybatis.ex01.b;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 1) jdbc.properties 파일을 추가한다.
// => 이 파일에 DB 접속 정보를 저장한다.
// 2) mybatis-config.xml 파일을 변경한다.
// => DB 접속 정보를 설정할 때 jdbc.properties 파일의 데이터를 사용한다.
//
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/b/mybatis-config.xml")).openSession();
System.out.println("mybatis 사용 준비 완료!");
sqlSession.close();
}
}
ex01/b/jdbc.properties
# jdbc.properties
driver=org.mariadb.jdbc.Driver
url=jdbc:mariadb://localhost:3306/studydb
username=study
password=1111
Mybatis 설정 파일 - SQL 매퍼 파일 설정과 SQL 문 사용법
package com.eomcs.mybatis.ex01.c;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/c/mybatis-config.xml")).openSession();
// 1) SQL 매퍼 파일 준비
// - mybatis.org 사이트에서 문서 페이지를 참조한다.
// - SQL이 들어 있는 파일(예: BoardMapper.xml)을 생성한다.
// - 문서 페이지를 참조하여 매퍼 파일의 내용을 변경한다.
// 2) select 결과를 저장할 클래스 정의
// - Board 클래스 생성
// 3) BoardMapper.xml 파일에 보관된 select 문 실행하기
// - SQL을 실행하고 결과 데이터를 객체에 담아 리턴한다.
// - mybatis 문서 페이지를 참조한다.
// - SqlSession.selectList("네임스페이스명.SQL아이디")
//
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
System.out.println(boards.size());
sqlSession.close();
}
}
ex01/c/BoardMapper.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">
<!-- SQL Mapper 파일:
=> SQL 문을 보관하는 파일이다.
=> SQL 문 종류에 따라 다른 태그를 사용한다.
<select>SELECT 문</select>
<insert>INSERT 문</insert>
<update>UPDATE 문</update>
<delete>DELETE 문</delete>
=> namespace 속성:
- SQL문이 소속된 그룹. 자바의 패키지명과 같은 역할을 한다.
- 보통 그룹명은 SQL 맵퍼 파일이름으로 지정한다.
- 다른 매퍼 파일과 구분하기 위해 파일의 경로명을 포함하기도 한다.
- 실무에서는 주로 SQL을 사용할 인터페이스나 클래스 경로를 그룹명으로 지정한다.
- 물론 어떤 이름으로 지정해도 상관없지만, 가능한 위의 규칙을 준수하는 것이 유지보수에 좋다.-->
<mapper namespace="BoardMapper">
<!-- select 태그:
=> select 문을 보관할 때 사용한다.
=> id 속성:
SQL문을 찾을 때 사용할 식별자.
=> resultType 속성:
select 결과(한 개의 레코드 값)를 담을 객체의 타입이다.
클래스명은 반드시 패키지 이름을 포함(fully-qualified name=FQName=QName)해야 한다.
-->
<select id="selectBoard" resultType="com.eomcs.mybatis.ex01.c.Board">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
order by board_id desc
</select>
</mapper>
ex01/c/Board.java
package com.eomcs.mybatis.ex01.c;
import java.io.Serializable;
import java.sql.Date;
public class Board implements Serializable {
private static final long serialVersionUID = 1L;
int no;
String title;
String content;
Date registeredDate;
int viewCount;
@Override
public String toString() {
return "Board [no=" + no + ", title=" + title + ", content=" + content + ", registeredDate="
+ registeredDate + ", viewCount=" + viewCount + "]";
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getRegisteredDate() {
return registeredDate;
}
public void setRegisteredDate(Date registeredDate) {
this.registeredDate = registeredDate;
}
public int getViewCount() {
return viewCount;
}
public void setViewCount(int viewCount) {
this.viewCount = viewCount;
}
}
Mybatis 설정 파일 - 도메인 클래스의 별명을 설정하는 방법과 사용법
package com.eomcs.mybatis.ex01.d;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 도메인 클래스의 별명을 부여하기
// - SQL 매퍼 파일에서 데이터를 리턴하거나 파라미터로 데이터를 받을 때
// 클래스의 전체 이름(패키지 이름을 포함)을 지정해야 한다.
// - 패키지 이름이 길 경우 사용하기가 번거롭다.
// - mybatis 설정 파일에서 fully-qualified class name 을 사용하는 대신에
// 짧은 이름으로 대체할 수 있다.
//
// 1) mybatis-config.xml 변경
// - 다음과 같이 클래스 전체 이름에 대해 별명을 지정한다.
//
// <typeAliases>
// <typeAlias type="com.eomcs.mybatis.ex01.d.Board" alias="board"/>
// </typeAliases>
//
// 2) BoardMapper.xml 변경
// - 결과를 담을 클래스를 지정할 때 클래스 전체 이름을 사용하는 대신에
// mybatis 설정 파일에 등록된 별명을 사용할 수 있다.
// - 다음과 같이 SQL 맵퍼 파일에서 클래스를 지정할 때 별명을 사용한다.
//
// <select id="selectBoard" resultType="board">
// select
// board_id as no,
// title,
// contents as content,
// created_date registeredDate,
// view_count viewCount
// from x_board
// </select>
//
// 참고!
// => 자바 primitive type과 wrapper 클래스, String 클래스,
// 일부 유틸리티 클래스 등에 대해서는 mybatis가 미리 별명을 지정하였다.
// => 예)
// int -> _int
// float -> _float
// java.lang.Integer -> int
// java.lang.Float -> float
// java.lang.String -> string
// java.util.Map -> map
// java.util.HashMap -> hashMap
//
//
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/d/mybatis-config.xml")).openSession();
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
System.out.println(boards.size());
sqlSession.close();
}
}
ex01/d/mybatis-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>
<properties resource="com/eomcs/mybatis/ex01/d/jdbc.properties"></properties>
<!-- SQL 맵퍼 파일에서 긴 이름의 클래스명을 사용하는 대신에 짧은 이름의 별명을 사용해보자! -->
<typeAliases>
<!-- 주의!
자바 클래스 이름을 지정할 때
패키지와 패키지 사이는 항상 . 으로 표기해야 한다.
/ 는 파일 경로를 가리킬 때 사용한다.
-->
<typeAlias type="com.eomcs.mybatis.ex01.d.Board" alias="board"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/eomcs/mybatis/ex01/d/BoardMapper.xml"/>
</mappers>
</configuration>
ex01/d/BoardMapper.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="BoardMapper">
<!-- 자바 클래스를 지정할 때 mybatis 설정 파일에 별명이 등록되어 있다면,
그 별명을 사용할 수 있다.
참고!
별명은 대소문자를 구분하지 않는다. -->
<select id="selectBoard" resultType="board">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
Mybatis 설정 파일 - 도메인 클래스의 별명을 설정하는 또 다른 방법
package com.eomcs.mybatis.ex01.e;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
// 패키지에 소속된 전체 클래스에 대해 별명을 자동으로 부여할 수 있다.
// => 단 별명은 클래스 이름이다.
//
// <typeAliases>
// <package name="com.eomcs.mybatis.ex01.e"/>
// </typeAliases>
//
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex01/e/mybatis-config.xml")).openSession();
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
System.out.println(boards.size());
sqlSession.close();
}
}
ex01/e/BoardMapper.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="BoardMapper">
<!-- 자동으로 등록된 클래스의 별명은 클래스 이름과 같다.
별명은 대소문자를 구분하지 않지만
가능한 클래스 이름을 그대로 사용한다. -->
<select id="selectBoard" resultType="board">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
ex01/e/mybatis-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>
<properties resource="com/eomcs/mybatis/ex01/e/jdbc.properties"></properties>
<typeAliases>
<!-- 패키지에 소속된 모든 클래스에 대해 별명을 자동으로 부여할 수 있다.
클래스 이름이 별명으로 설정된다.-->
<package name="com.eomcs.mybatis.ex01.e"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/eomcs/mybatis/ex01/e/BoardMapper.xml"/>
</mappers>
</configuration>
com.eomcs.mybatis.ex02
ex02/a/BoardMapper.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="BoardMapper">
<!-- SQL문은 태그 안에 작성한다.
<select> 태그에는 select 문장을,
<insert> 태그에는 insert 문장을,
<update> 태그에는 update 문장을,
<delete> 태그에는 delete 문장을 작성한다.
그런데 insert/update/delete 인 경우
<insert>/<update>/<delete> 구분없이 태그를 사용해도 된다.
그 이유는 SQL문을 찾을 때 id 속성 값으로 찾기 때문이다.
그럼에도 불구하고 유지보수의 일관성을 위해
SQL 문의 따라 적절한 태그를 사용하라!
-->
<select id="selectBoard" resultType="Board">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
SqlSession 사용법 - SQL 문을 실행하는 메서드
package com.eomcs.mybatis.ex02.a;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/a/mybatis-config.xml")).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> boards = sqlSession.selectList("BoardMapper.selectBoard");
System.out.println(boards.size());
sqlSession.close();
}
}
ex02/b/BoardMapper.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="BoardMapper">
<!-- select 태그
id : SQL문을 찾을 때 사용할 식별자이다.
resultType : select 결과를 저장할 클래스이름이나 별명이다.
클래스 이름은 반드시 fully-qualified class name(패키지명을 포함한 클래스명)을 사용하라!
-->
<select id="selectBoard" resultType="Board">
select
board_id, <!-- Board.setBoard_id() 호출 -->
title, <!-- Board.setTitle() 호출 -->
contents, <!-- Board.setContents() 호출 -->
created_date, <!-- Board.setCreated_date() 호출 -->
view_count <!-- Board.setView_count() 호출 -->
from x_board
</select>
<!--
값을 자바 객체에 넣는 규칙:
=> 컬럼명과 일치하는 셋터를 호출한다.
컬럼명 ==> set컬럼명()
=> 예)
bno ==> setBno(값)
즉,
Board board = new Board();
board.setBno(rs.getNo("bno"));
만약 컬럼 이름에 해당하는 셋터를 못 찾으면 호출하지 않는다.
-->
<!-- 위의 SQL문을 mybatis는 내부에서
다음과 같은 코드로 실행할 것이다.
ArrayList<Board> list = new ArrayList<>();
while (rs.next()) {
Board board = new Board();
board.setBoard_id(rs.getNo("board_id")); // 이런 셋터가 없다.
board.setTitle(rs.getString("title")); // 이 셋터는 있다.
board.setContents(rs.getString("contents")); // 이런 셋터가 없다.
board.setCreated_date(rs.getDate("created_date")); // 이런 셋터가 없다.
board.setView_count(rs.getDate("view_count")); // 이런 셋터가 없다.
list.add(board);
}
return list;
그러나 안타깝게도 Board 클래스에는 컬럼 이름과 일치하는 셋터가
딱 한개만 있다. title 컬럼이다.
그 외 컬럼 값은 셋터가 없기 때문에 저장할 수 없다.
해결책?
=> 셋터의 이름(프로퍼티 이름)과 같은 이름으로 컬럼의 별명을 설정하라!
-->
</mapper>
SqlSession.selectList() 사용법 - select 문 실행하기
package com.eomcs.mybatis.ex02.b;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/b/mybatis-config.xml")).openSession();
// selectList()
// => 여러 개의 결과 값을 리턴하는 select를 실행할 때 사용한다.
// => select 실행으로 생성된 각 row의 값은 resultType에 지정한 클래스의 인스턴스에 저장된다.
// => 그리고 그 인스턴스는 List 구현체에 담겨 리턴된다.
// => 결과가 없으면 size 가 0인 List 객체를 리턴한다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
for (Board b : boards) {
System.out.println(b);
// System.out.printf("%d,%s,%s,%s,%d\n",
// b.getNo(),
// b.getTitle(),
// b.getContent(),
// b.getRegisteredDate(),
// b.getViewCount());
}
// 실행 결과가 기대와 같지 않은 이유?
// => mybatis에서 결과 값을 Board 객체에 담을 때 일부 컬럼의 값을 담지 못했기 때문이다.
//
// 왜 일부 컬럼의 값을 Board에 담지 못했는가?
// => mybatis에서 결과의 컬럼 값을 자바 객체에 담을 때
// 컬럼 이름과 같은 이름을 가진 프로퍼티(셋터 메서드)를 찾는다.
// => 컬럼 이름과 일치하는 프로퍼티가 없다면,
// 컬럼 이름과 일치하는 필드를 찾는다.
// => 컬럼 이름과 일치하는 세터나 필드가 없다면
// 해당 컬럼의 값이 자바 객체에 저장되지 못한다.
// => 컬럼과 일치하는 프로퍼티나 필드가 한 개도 없다면,
// 자바 객체를 만들지 않고 null을 리턴한다.
sqlSession.close();
}
}
Mybatis에서 select 결과를 자바 인스턴스에 담을 때 규칙
=> 컬럼 이름과 같은 프로퍼티를 찾아서 값을 담는다.
=> 자바에서 '프로퍼티'란?
세터/게터를 가리키는 용어다.
예) setNo()/getNo()
=> 프로퍼티 이름?
세터/게터 이름에서 set/get 이름을 제거한 후, 나머지 이름이다.
단 첫 알파벳은 소문자이다.
예) setNo()/getNo() => no
예) setCreatedDate()/getCreatedDate() => createdDate
=> 주의!
필드 이름이 프로퍼티 이름이 아니다!
결론!
- Board 클래스의 프로퍼티 이름을 보면
no, title, content, registeredDate, viewCount 가 있다.
- Board 클래스의 필드 이름을 보면
no, title, content, registeredDate, viewCount 가 있다.
- 이 프로퍼티나 필드 중에서 컬럼 이름과 일치하는 프로퍼티나 필드는 title 뿐이다.
- Mybatis는 컬럼 이름과 같은 이름을 가진
프로퍼티(title,contents) 또는 필드에 대해서만 결과 값을 넣어 준다.
- 그래서 Board 객체를 출력해보면 title 값만 정상적으로 출력된다.
해결책?
=> 컬럼 이름을 프로퍼티명이나 필드명과 같게 하라.
- DB의 이름짓는 규칙과 자바의 이름 짓는 규칙은 다르다.
- 또한 DBMS 마다 이름 짓는 규칙이 다르다.
- 그래서 자바에서 프로퍼티 이름을 지을 때는 특정 DBMS에 종속되게 지어서는 안된다.
- 자바는 자바의 명명 규칙을 따르고, DB는 DBMS의 명명 규칙을 따르면 된다.
=> 그러면 어떻게 하자는 것인가?
- select 할 때 컬럼의 별명을 자바 프로퍼티(또는 필드) 이름과 같게 하라!
ex02/c/BoardMapper.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="BoardMapper">
<!--
컬럼명을 자바 객체의 프로퍼티명(셋터명)과 일치시키기:
컬럼의 이름이 프로퍼티(또는 필드) 이름과 다르다면,
객체에 값을 넣을 수 없다.
컬럼 이름을 프로퍼티(또는 필드) 이름과 일치시켜야만 정확하게 값을 객체에 담을 수 있다.
select 문에서 컬럼의 별명을 프로퍼티명(또는 필드명)과 같게 하라!
-->
<select id="selectBoard" resultType="Board">
select
board_id as no, <!-- Board.setNo() 호출 -->
title, <!-- Board.setTitle() 호출 -->
contents as content, <!-- Board.setContent() 호출 -->
created_date as registeredDate, <!-- Board.setRegisteredDate() 호출 -->
view_count as viewCount <!-- Board.setViewCount() 호출 -->
from x_board
</select>
</mapper>
SqlSession.selectList() 사용법 - 컬럼 별명을 이용하여 자바 객체의 프로퍼티 이름과 일치시키기
package com.eomcs.mybatis.ex02.c;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/c/mybatis-config.xml")).openSession();
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
// select 문에서 컬럼을 지정할 때 자바 인스턴스의 프로퍼티 이름과 다르다면
// 별명을 이용하여 프로퍼티명과 같게 한다.
// 컬러몀과 자바 객체의 프로퍼티명이 일치한다면 다음과 같이 정상적으로 데이터를 꺼내올 수 있다.
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.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>
//---------------------------------------------------------------------
//=> 컬럼의 값을 자바 객체에 담으려면 컬럼과 같은 이름의 프로퍼티가 있어야 한다.
//=> 없다면 위와 같이 프로퍼티 명을 컬럼의 별명으로 지정하라.
ex02/d/BoardMapper.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="BoardMapper">
<!-- 컬럼명과 자바 객체의 프로퍼티 명을 미리 연결한다.
type: 자바 객체의 클래스명 또는 별명
id: 연결 정보를 가리키는 식별자. SQL 문을 설정할 때 사용한다.
-->
<resultMap type="Board" id="BoardMap">
<!-- 컬럼명과 자바 객체의 프로퍼티명을 연결한다.
column="테이블 컬럼명"
property="자바 객체의 프로퍼티명"
시작태그와 끝태그 사이에 추가 내용이 없다면 끝태그를 생략하고
대신에 시작태그의 끝에 /를 붙인다.
PK 컬럼을 지정할 때는 id 엘리먼트를 사용하고,
일반 컬럼을 지정할 때는 result 엘리먼트를 사용하라! -->
<id column="board_id" property="no"/>
<!-- 의미 => board_id 컬럼 값은 Board.setNo()을 호출해서 넣으라는 의미 -->
<!-- 컬럼 이름과 자바 객체의 프로퍼티 이름이 같을 경우 생략해도 된다. -->
<!--
<result column="title" property="title"/>
-->
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- 위에서 정의한 연결 정보를 사용하고 싶다면,
resultMap="컬럼과 프로퍼티의 연결을 정의한 resultMap 아이디" 를 설정하라!
참고!
resultType="클래스명 또는 별명"
-->
<select id="selectBoard" resultMap="BoardMap">
select
board_id, <!-- BoardMap의 연결정보를 참조하기 때문에 별명을 주지 않아도 된다. -->
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
SqlSession.selectList() 사용법 - <resultMap>을 통해 자바 객체의 프로퍼티 이름과 일치시키기
package com.eomcs.mybatis.ex02.d;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/d/mybatis-config.xml")).openSession();
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard");
// select 문에서 컬럼 값을 자바 인스턴스의 프로퍼티와 맞추기 위해
// 별명을 부여하는 방식은 번거롭다.
// 특히 컬럼 개수가 많은 경우 더더욱 번거롭다.
// 이를 해결하기 위해 mybatis는 컬럼의 이름과 프로퍼티 이름을 연결해주는 문법을 제공한다.
// <resultMap></resultMap>
//
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
ex02/e/BoardMapper.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="BoardMapper">
<!-- select 결과를 Map 객체에 받을 수 있다.
- 각각의 레코드 값은 각각의 Map 객체에 보관된다.
- 그리고 List에 Map 객체 목록이 보관된다.
-->
<select id="selectBoard" resultType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
SqlSession.selectList() 사용법 - 결과 레코드를 Map 객체로 받기
package com.eomcs.mybatis.ex02.e;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/e/mybatis-config.xml")).openSession();
// 결과 타입이 Map 이면,
// - selectList()의 리턴 타입은 List<Map> 이 된다.
//
List<Map<String,Object>> list = sqlSession.selectList("BoardMapper.selectBoard");
// 각각의 Map 객체에는 레코드 값이 보관되어 있다.
// - 즉 레코드의 각 컬럼 값이 Map 객체에 보관되어 있다.
// - 컬럼 값을 꺼낼 때는 select 할 때 사용한 컬럼이름으로 꺼내야 한다.
//
for (Map<String,Object> map : list) {
System.out.printf("%d,%s,%s,%s,%d\n",
map.get("board_id"),
map.get("title"),
map.get("contents"),
map.get("created_date"),
map.get("view_count"));
}
sqlSession.close();
}
}
ex02/f/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- select 문의 실행 결과가 1개 인 경우 -->
<select id="selectBoard1" resultMap="BoardMap">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id=1
</select>
<!-- select 문의 실행 결과가 없을 경우 -->
<select id="selectBoard2" resultMap="BoardMap">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id=100
</select>
<!-- 결과를 Map 객체로 리턴 받을 수 있다. -->
<select id="selectBoard3" resultType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id=1
</select>
<!-- select 문의 실행 결과가 2개 이상일 때는 selectOne() 으로 실행할 수 없다. -->
<select id="selectBoard4" resultMap="BoardMap">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</select>
</mapper>
SqlSession.selectOne() 사용법 - 한 개의 결과를 조회할 때 사용
package com.eomcs.mybatis.ex02.f;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/f/mybatis-config.xml")).openSession();
// selectOne()
// - select 결과가 0 또는 1개 일 때 호출할 수 있다.
//
Board b = sqlSession.selectOne("BoardMapper.selectBoard1");
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
sqlSession.close();
}
}
SqlSession.selectOne() 사용법 - 결과가 0 개 일 때
package com.eomcs.mybatis.ex02.f;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/f/mybatis-config.xml")).openSession();
// selectOne()
// - select 결과가 0 또는 1개 일 때 호출할 수 있다.
// - 결과가 없으면 리턴 값은 null 이다.
//
Board b = sqlSession.selectOne("BoardMapper.selectBoard2");
if (b == null) {
System.out.println("해당 번호의 게시글이 없습니다.");
return;
}
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
sqlSession.close();
}
}
SqlSession.selectOne() 사용법 - 결과 값을 Map 객체로 받기
package com.eomcs.mybatis.ex02.f;
import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0210 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/f/mybatis-config.xml")).openSession();
// Map 객체로 받으려면 SQL 매퍼에서 다음과 같이 resultType을 설정해야 한다.
// <select id="selectBoard3" resultType="map" parameterType="int">
// select
// board_id,
// title,
// contents,
// created_date,
// view_count
// from x_board
// where board_id=#{no}
// </select>
//
// - 컬럼 이름(이나 별명)으로 컬럼 값을 저장하기 때문에
// map 객체에 컬럼 값을 꺼낼 때 컬럼 이름(이나 별명)을 사용해야 한다.
//
Map<String,Object> map = sqlSession.selectOne("BoardMapper.selectBoard3");
if (map == null) {
System.out.println("해당 번호의 게시글이 없습니다.");
return;
}
System.out.printf("%d,%s,%s,%s,%d\n",
map.get("board_id"),
map.get("title"),
map.get("contents"),
map.get("created_date"),
map.get("view_count"));
sqlSession.close();
}
}
SqlSession.selectOne() 사용법 - 한 개를 초과한 개수의 결과를 조회할 때
package com.eomcs.mybatis.ex02.f;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0310 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex02/f/mybatis-config.xml")).openSession();
// selectOne()
// - 여러 개의 결과가 나오는 select 문에 대해 호출하면 예외가 발생한다.
//
Board b = sqlSession.selectOne("BoardMapper.selectBoard4");
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
sqlSession.close();
}
}
com.eomcs.mybatis.ex03
ex03/a/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- SQL 문에 값 삽입하기 : in-parameter 지정하기
=> parameterType에 지정된 객체의 프로퍼티 명을 사용하여 값을 삽입한다.
예) #{프로퍼티명}
=> paramterType이 primitive/String/wrapper class 인 경우 아무 이름을 적어도 된다.
예) #{아무이름}
=> parameterType이 Map 객체인 경우는 Map에 저장된 값의 key를 적는다.
예) #{key}
=> parameterType에 지정할 수 있는 타입:
int => _int
Integer => int
String => string
Map => map
HashMap => hashmap
Board => board
...
-->
<!-- selectOne(sqlid, int) -->
<select id="select1" resultMap="BoardMap" parameterType="int">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id=#{hoho}
</select>
<!-- selectList(sqlid, string) -->
<select id="select2" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where title=#{okok}
</select>
<!-- selectList(sqlid, int) -->
<select id="select3" resultMap="BoardMap" parameterType="int">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id < #{hul}
</select>
<!-- selectList(sqlid, int) -->
<select id="select4" resultMap="BoardMap" parameterType="int">
<![CDATA[
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id < #{no}
]]>
</select>
</mapper>
SQL 문에 삽입할 파라미터 전달하기 - 한 개의 int 값 넘기기
package com.eomcs.mybatis.ex03.a;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/a/mybatis-config.xml")).openSession();
// in-parameter에 int 값 넘기기
// => SQL을 실행할 때 파라미터 값을 전달하려면
// 두 번째 파라미터로 전달해야 한다.
// 예) selectOne(sqlID, in-parameter 값)
// => in-parameter 값의 타입은 Object이다.
// 자바 원시 타입의 값을 지정하면 자동으로 오토 박싱되어 mybatis에 전달된다.
// => 여러 개의 값을 전달해야 한다면,
// 도메인 객체나 Map 객체에 담아 전달하라!
// 예) 특정 번호의 게시글을 가져온다.
Board board = sqlSession.selectOne("BoardMapper.select1", 5); // auto-boxing 수행
if (board != null) {
System.out.printf("%d,%s,%s,%s,%d\n",
board.getNo(),
board.getTitle(),
board.getContent(),
board.getRegisteredDate(),
board.getViewCount());
}
sqlSession.close();
System.out.println("실행 완료!");
}
}
SQL 문에 삽입할 파라미터 전달하기 - 한 개의 String 값 넘기기
package com.eomcs.mybatis.ex03.a;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/a/mybatis-config.xml")).openSession();
// 예) 특정 제목의 게시글을 가져온다.
List<Board> boards = sqlSession.selectList("BoardMapper.select2", "제목2");
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
System.out.println("실행 완료!");
}
}
SQL 문에 삽입할 파라미터 전달하기 - XML Entity를 사용할 때
package com.eomcs.mybatis.ex03.a;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0130 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/a/mybatis-config.xml")).openSession();
// XML 파서가 혼동을 일으킬 수 있는(XML 파싱 오류 발생) 문자를 사용할 때,
// 그 문자 대신 XML Entity를 사용하라.
// " => "
// ' => '
// & => &
// < => <
// > => >
//
// 예) 특정 번호 미만의 게시글을 가져온다.
List<Board> boards = sqlSession.selectList("BoardMapper.select3", 3);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
System.out.println("실행 완료!");
}
}
SQL 문에 삽입할 파라미터 전달하기 - CDATA 섹션을 사용할 때 : <[!CDATA[ SQL 문 []]>
package com.eomcs.mybatis.ex03.a;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0140 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/a/mybatis-config.xml")).openSession();
// CDATA 섹션
// - XML 파서(parser)에게 해당 블록의 내용물이 단순 텍스트임을 알려주는 명령이다.
// - 문법
// <![CDATA[ 내용물 ]]>
// - 내용물 안에 XML 파서가 혼동을 일으킬 문자가 많을 때 사용하기 적합하다.
//
// 예) 특정 번호 미만의 게시글을 가져온다.
List<Board> boards = sqlSession.selectList("BoardMapper.select4", 3);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
System.out.println("실행 완료!");
}
}
ex03/b/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- selectList(sqlid, Map)
=> Map에서 값을 꺼낼 때는 값을 저장할 때 사용한 key를 이용한다.
=> #{key}
-->
<select id="select1" resultMap="BoardMap" parameterType="map">
<![CDATA[
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id >= #{startNo} and board_id <= #{endNo}
]]>
</select>
<!-- 일반 객체를 파라미터로 받을 수 있다.
parameterType="클래스명 또는 별명"
일반 객체에서 값을 꺼내려면 프로퍼티(getter)명을 지정해야 한다.
예)
#{title} ==> getTitle()의 리턴 값을 의미한다.
#{content} ==> getContent()의 리턴 값을 의미한다.
-->
<!-- insert(sqlId, Board) -->
<insert id="insert" parameterType="board">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
</mapper>
SQL 문에 삽입할 파라미터 전달하기 - Map을 이용하여 여러 개의 값 넘기기
package com.eomcs.mybatis.ex03.b;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/b/mybatis-config.xml")).openSession();
// selectList(),selectOne(),insert(),update(),delete()
// - selectList(SQL ID)
// - selectList(SQL ID, 파라미터)
// - 위와 같이 SQL을 실행할 때 오직 한 개의 파라미터만 넘길 수 있다.
// - 여러 개의 파라미터를 넘기고 싶다면 객체에 담아서 넘겨라!
//
// 예) 특정 범위의 번호에 해당하는 게시글을 가져온다.
//
Map<String,Object> params = new HashMap<>();
params.put("startNo", 2);
params.put("endNo", 4);
List<Board> boards = sqlSession.selectList("BoardMapper.select1", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
System.out.println("실행 완료!");
}
}
SQL 문에 삽입할 파라미터 전달하기 - 일반 객체를 이용하여 여러 개의 값 넘기기
package com.eomcs.mybatis.ex03.b;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/b/mybatis-config.xml")).openSession();
// Board 객체에 값을 저장하여 전달하기
// - 단 값을 꺼낼 수 있도록 겟터(프로퍼티)가 있어야 한다.
//
Board board = new Board();
board.setTitle("제목입니다");
board.setContent("내용입니다.");
// insert 문을 실행할 때는 insert() 메서드를 호출한다.
// - 리턴 값은 executeUpdate()의 실행 결과이다.
// - 즉 insert 된 데이터의 개수이다.
//
// 예) 게시글을 입력한다.
//
int count = sqlSession.insert("BoardMapper.insert", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
// 현재 SqlSession 객체가 수동 commit 상태이기 때문에
// 데이터 변경을 수행한 후 commit을 반드시 실행해야 한다.
//
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
ex03/c/BoardMapper.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="BoardMapper">
<!-- insert(sqlId, Board) -->
<insert id="insert1" parameterType="board">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
<!-- insert(sqlId, Map) -->
<insert id="insert2" parameterType="map">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
<!-- insert(sqlId, Board) -->
<insert id="insert3" parameterType="board"
useGeneratedKeys="true" keyColumn="board_id" keyProperty="no">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
<!-- update(sqlId, Board) -->
<update id="update" parameterType="board">
update x_board set
title=#{title},
contents=#{content}
where
board_id=#{no}
</update>
<!-- delete(sqlId, no) -->
<delete id="delete" parameterType="int">
delete from x_board
where
board_id=#{no}
</delete>
</mapper>
insert 문 실행 - Board 객체에 값을 담아 파라미터로 넘기기
package com.eomcs.mybatis.ex03.c;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/c/mybatis-config.xml")).openSession();
Board board = new Board();
board.setTitle("제목입니다111"); // #{title} 을 사용하여 SQL 문에 값을 삽입한다.
board.setContent("내용입니다111."); // #{content} 를 사용하여 SQL 문에 값을 삽입한다.
// insert 문을 실행할 때는 insert() 메서드를 호출한다.
// - 리턴 값은 executeUpdate()의 실행 결과이다.
// - 즉 insert 된 데이터의 개수이다.
// - update(), delete()을 사용해도 결과는 같다.
//
// 예) 게시글을 입력한다.
//
int count = sqlSession.insert("BoardMapper.insert1", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
// SqlSessionFactory의 openSession()을 통해 SqlSession 얻을 때는
// autocommit이 기본으로 false이다.
// autocommit?
// - insert/update/delete 과 같이 데이터를 변경하는 작업은
// 위험하기 때문에 DBMS의 임시 메모리에 그 작업 결과를 보관한다.
// - 클라이언트에서 최종적으로 변경 사항에 대해 확정해줘야만 진짜 테이블에 값을 반영한다.
//
// 현재 SqlSession 객체가 수동 commit 상태이기 때문에
// 데이터 변경을 수행한 후 commit을 반드시 실행해야 한다.
//
sqlSession.commit();
// commit 명령을 내리지 않으면 insert/update/delete을 통해 수행한 데이터 변경 작업을
// 실제 테이블에 반영하지 않는다.
// close() 할 때 자동으로 취소된다.
//
// 용어 정리!
// commit() : 임시 메모리에 저장된 작업 결과를 실제 테이블에 반영시키는 명령
// rollback() : 임시 메모리에 저장된 작업 결과를 취소하는 명령
//
sqlSession.close();
System.out.println("실행 완료!");
}
}
insert 문 실행 - Map 객체에 값을 담아 파라미터로 넘기기
package com.eomcs.mybatis.ex03.c;
import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0120 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/c/mybatis-config.xml")).openSession();
HashMap<String,Object> params = new HashMap<>();
params.put("title", "제목입니다222"); // #{title} 을 사용하여 SQL 문에 값을 삽입한다.
params.put("content", "내용입니다222."); // #{content} 를 사용하여 SQL 문에 값을 삽입한다.
// 예) 게시글을 입력한다.
//
int count = sqlSession.insert("BoardMapper.insert2", params);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
update 문 실행
package com.eomcs.mybatis.ex03.c;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0210 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/c/mybatis-config.xml")).openSession();
Board board = new Board();
board.setNo(1); // #{no}
board.setTitle("제목 변경!!!"); // #{title}
board.setContent("내용 변경!!!"); // #{content}
// update 문을 실행할 때는 update() 메서드를 호출한다.
// - 리턴 값은 executeUpdate()의 실행 결과이다.
// - 즉 update 된 데이터의 개수이다.
//
// 예) 게시글을 변경한다.
//
int count = sqlSession.update("BoardMapper.update", board);
System.out.printf("%d 개의 데이터를 변경 했음!\n", count);
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
delete 문 실행
package com.eomcs.mybatis.ex03.c;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0310 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/c/mybatis-config.xml")).openSession();
// delete 문을 실행할 때는 delete() 메서드를 호출한다.
// - 리턴 값은 executeUpdate()의 실행 결과이다.
// - 즉 delete 된 데이터의 개수이다.
//
// 예) 게시글을 삭제한다.
//
int count = sqlSession.delete("BoardMapper.delete", 10);
System.out.printf("%d 개의 데이터를 삭제 했음!\n", count);
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
insert 문 실행 - INSERT 실행 후 자동 증가된 PK값 가져오기
package com.eomcs.mybatis.ex03.c;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0410 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/c/mybatis-config.xml")).openSession();
Board board = new Board();
board.setTitle("제목입니다333");
board.setContent("내용입니다333.");
System.out.printf("insert 실행 전: %s\n", board);
// insert 문을 실행한 후에 자동 증가한 PK 값을 알아내기
// - 자동 증가한 PK 값은 SQL을 실행할 때 넘겨준 객체에 담겨있을 것이다.
// - 단 SQL 매퍼 파일에서 insert 문을 정의할 때 설정해 줘야 한다.
// <insert id="insert3" parameterType="board"
// useGeneratedKeys="true"
// keyColumn="board_id"
// keyProperty="no">
// insert into x_board(title,contents,created_date)
// values(#{title}, #{content}, now())
// </insert>
//
// - useGeneratedKeys 속성: 자동 증가한 PK 컬럼 값을 사용할 것인지 지정한다.
// - keyColumn 속성 : 자동 증가 pk 컬럼의 이름을 지정한다.
// - keyProperty 속성 : 자동 증가 pk 컬럼의 값을 저장할 자바 객체의 프로퍼티를 지정한다.
//
// 예) 게시글을 입력한다.
//
int count = sqlSession.insert("BoardMapper.insert3", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
sqlSession.commit();
sqlSession.close();
System.out.printf("insert 실행 후: %s\n", board);
System.out.println("실행 완료!");
}
}
ex03/d/BoardMapper.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="BoardMapper">
<!-- insert(sqlId, Board) -->
<insert id="insert" parameterType="board">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
</mapper>
트랜잭션 다루기 - openSession(true) : 자동 커밋 SqlSession 객체 얻기
package com.eomcs.mybatis.ex03.d;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
// openSession(auto commit 여부)
// - true : 데이터 변경 후 즉시 커밋한다.
// - false : 데이터 변경 후 commit()을 호출할 때까지 실제 테이블에 변경 사항을 반영하지 않는다.
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession(true);
Board board = new Board();
board.setTitle("제목입니다xxx");
board.setContent("내용입니다xxx.");
int count = sqlSession.insert("BoardMapper.insert", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
// commit() 을 호출하지 않아도 즉시 테이블에 변경 사항을 반영한다.
sqlSession.close();
System.out.println("실행 완료!");
}
}
트랜잭션 다루기 - openSession() : 수동 커밋
package com.eomcs.mybatis.ex03.d;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
// openSession(auto commit 여부)
// - true : 데이터 변경 후 즉시 커밋한다.
// - false : 데이터 변경 후 commit()을 호출할 때까지 실제 테이블에 변경 사항을 반영하지 않는다.
//
// openSession()
// - 기본이 수동 커밋이다.
// - openSession(false) 와 같다.
//
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession();
Board board = new Board();
board.setTitle("제목입니다yyy");
board.setContent("내용입니다yyy");
int count = sqlSession.insert("BoardMapper.insert", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
// commit() 을 호출하지 않으면 테이블에 변경 사항을 반영하지 않는다.
sqlSession.close();
System.out.println("실행 완료!");
}
}
트랜잭션 다루기 - commit() : 데이터 변경 결과를 실제 테이블에 반영하기
package com.eomcs.mybatis.ex03.d;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0130 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/d/mybatis-config.xml")).openSession();
Board board = new Board();
board.setTitle("제목입니다zzz");
board.setContent("내용입니다zzz");
int count = sqlSession.insert("BoardMapper.insert", board);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
// 수동 커밋 상태일 때는
// - 데이터 변경 후 commit() 을 명시적으로 호출해야 한다.
// - 그래야 실제 테이블에 변경 사항이 반영된다.
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
ex03/e/BoardMapper.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="BoardMapper">
<!-- 부모 테이블 데이터 입력 : 게시글 입력 -->
<insert id="insertBoard" parameterType="board"
useGeneratedKeys="true" keyColumn="board_id" keyProperty="no">
insert into x_board(title,contents,created_date)
values(#{title}, #{content}, now())
</insert>
<!-- 자식 테이블 데이터 입력 : 첨부파일 입력 -->
<insert id="insertFile" parameterType="map">
insert into x_board_file(file_path, board_id)
values(#{filePath},#{boardNo})
</insert>
</mapper>
트랜잭션 다루기 - 수동 커밋의 필요성
package com.eomcs.mybatis.ex03.e;
import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/e/mybatis-config.xml")).openSession(true);
// 1) 게시글 입력
Board board = new Board();
board.setTitle("게시글1");
board.setContent("내용1");
int count = sqlSession.insert("BoardMapper.insertBoard", board);
System.out.printf("%d 개의 게시글을 입력 했음!\n", count);
HashMap<String,Object> fileInfo = new HashMap<>();
// 2) 첫 번째 첨부파일 입력
fileInfo.put("filePath", "aaa.gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// 3) 두 번째 첨부파일 입력
fileInfo.put("filePath", "bbb.gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// 4) 세 번째 첨부파일 입력
fileInfo.put("filePath",
"12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ ".gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// auto commit 일 때,
// - 데이터 변경 SQL 문을 실행하면 즉시 테이블에 적용한다.
// - 따라서 세 번째 첨부파일을 입력하다가 오류가 발생하더라도
// 이전에 수행했던 데이터 변경 작업은 완료된 상태다.
//
sqlSession.close();
System.out.println("실행 완료!");
}
}
트랜잭션 다루기 - 수동 커밋의 활용
package com.eomcs.mybatis.ex03.e;
import java.util.HashMap;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
// 수동 커밋 상태로 동작하는 SqlSession 객체를 얻는다.
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/e/mybatis-config.xml")).openSession();
// 1) 게시글 입력
Board board = new Board();
board.setTitle("게시글2");
board.setContent("내용2");
int count = sqlSession.insert("BoardMapper.insertBoard", board);
System.out.printf("%d 개의 게시글을 입력 했음!\n", count);
HashMap<String,Object> fileInfo = new HashMap<>();
// 2) 첫 번째 첨부파일 입력
fileInfo.put("filePath", "aaa.gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// 3) 두 번째 첨부파일 입력
fileInfo.put("filePath", "bbb.gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// 4) 세 번째 첨부파일 입력
fileInfo.put("filePath",
"12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ ".gif");
fileInfo.put("boardNo", board.getNo());
count = sqlSession.insert("BoardMapper.insertFile", fileInfo);
System.out.printf("%d 개의 첨부파일을 입력 했음!\n", count);
// 수동 commit 일 때,
// - 작업을 완료한 후 반드시 commit()을 호출해야만 실제 테이블에 변경사항을 적용한다.
// - commit() 을 호출하지 않고 SqlSession 객체를 close() 하면 자동 rollback 이다.
// - SqlSession 객체를 재사용하는 방식이면,
// 오류가 발생했을 때 개발자가 명시적으로 rollback()을 호출해 줘야 한다.
//
sqlSession.commit();
sqlSession.close();
System.out.println("실행 완료!");
}
}
ex03/f/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- #{} 을 사용하여 값이 아닌 SQL 코드를 삽입할 수 있는가?
=> 없다! 오류 발생!!!
[#{} 문법의 한계]
in-parameter 는 컬럼의 값을 지정할 때 사용한다.
그리고 in-parameter 자리에 값을 놓을 때는 #{프로퍼티명} 문법을 사용한다.
select *
from x_board
where title = #{value}
그러나 테이블 이름이나 컬럼 이름,
SQL 키워드(예: select, from, insert, values, into, set, asc, desc, order, by 등)가 들어갈 자리는
in-parameter로 지정할 수 없다.
in-parameter로 지정할 수 없는 자리에 #{프로퍼티명}을 사용할 수 없다.
select *
from #{name} <==== 안된다!
where title = #{value}
order by
#{column} #{sort} <==== 둘 다 안된다.
-->
<select id="select1" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
order by board_id #{sortType}
</select>
<!-- 문자열 치환 문법(${})으로 SQL 코드를 삽입하기
=> SQL 키워드(테이블 이름과 컬럼 이름 포함)가 들어갈 자리에
in-parameter 처럼 값을 넣고 싶다면 ${프로퍼티명} 을 사용하라!
[경고!]
=> 사용자가 입력한 값을 직접 SQL 코드에 삽입하는 경우 "SQL 삽입 공격"을 받을 수 있다.
=> 따라서 ${프로퍼티명} 문법을 사용할 때는 절대로 사용자가 입력한 값을 그대로 전달하지 말라!
=> 사용자가 입력한 값을 자바 코드에서 판단하여 자바 코드로 입력한 값을 전달하라!
-->
<select id="select2" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
order by board_id ${sortType}
</select>
<!--
${} 는 SQL 코드를 삽입할 수 있다.
-->
<select id="select3" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
order by ${sort}
</select>
<!--
${} 는 SQL 코드를 삽입할 수 있다.
-->
<select id="select4" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
order by ${columnName} ${sortType}
</select>
<!--
${} 는 SQL 코드를 삽입할 수 있다.
-->
<select id="count" resultType="int" parameterType="string">
select
count(*)
from ${tableName}
</select>
<delete id="delete1" parameterType="string">
delete from x_board
where title = #{value}
</delete>
<delete id="delete2" parameterType="string">
delete from x_board
where ${condition}
</delete>
</mapper>
#{} 문법의 한계
package com.eomcs.mybatis.ex03.f;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession();
// 정렬 방식을 파라미터로 넘기기
// => #{} 문법은 오직 값만 삽입할 수 있다.
// => SQL 코드를 삽입할 수 없다.
// => 파라미터 값을 SQL에 그대로 삽입하려면
// 문자열 치환 문법인 ${} 를 사용해야 한다.
List<Board> boards = sqlSession.selectList("BoardMapper.select1", "desc");
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
${} 문법 : 문자열 치환(string substitution) 문법의 활용
package com.eomcs.mybatis.ex03.f;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession();
// 문자열 치환(string substitution) 문법(${})을 사용하면 SQL 코드를 파라미터로 넘길 수 있다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.select2", "desc");
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
${} 문법 : 문자열 치환(string substitution) 문법의 활용 II
package com.eomcs.mybatis.ex03.f;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0130 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession();
// 정렬 방식을 파라미터로 넘기기
// => ${} 문법은 파라미터 값을 SQL 문에 그대로 삽입한다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.select3",
"created_date desc, title asc");
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
${} 문법 : 문자열 치환(string substitution) 문법의 활용 IV
package com.eomcs.mybatis.ex03.f;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0140 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession();
// 컬럼 이름과 정렬 타입을 파라미터로 넘기기
//
HashMap<String,Object> params = new HashMap<>();
params.put("columnName", "title");
params.put("sortType", "asc");
List<Board> boards = sqlSession.selectList("BoardMapper.select4", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
${} 문법 : 문자열 치환(string substitution) 문법의 활용 III
package com.eomcs.mybatis.ex03.f;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0150 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession();
// 테이블명을 파라미터로 넘기기
// => ${} 문법은 파라미터 값을 SQL 문에 그대로 삽입한다.
//
int count = sqlSession.selectOne("BoardMapper.count", "x_board");
System.out.println(count);
sqlSession.close();
${} 문법의 위험성 - #{} 사용할 때
package com.eomcs.mybatis.ex03.f;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0210 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("삭제할 게시글의 제목? ");
String input = keyboard.nextLine();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession(true);
// #{} 문법은 SQL에 값을 삽입할 때 사용한다.
// 사용자가 입력한 값(문자열)에 sql 코드를 포함하더라도
// 그냥 값으로 취급하기 때문에 실행에는 영향을 끼치지 않는다.
// 즉 'SQL 삽입 공격'이 불가능하다.
// 삭제할 게시글의 제목에 SQL에 영향을 끼치는 코드를 삽입하여 실행해 보라!
// => 어떤 영향도 주지 못할 것이다.
int count = sqlSession.delete("BoardMapper.delete1", input);
System.out.println(count);
sqlSession.close();
keyboard.close();
}
}
${} 문법의 위험성 - ${} 사용할 때
package com.eomcs.mybatis.ex03.f;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Exam0220 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n 3. 번호\n검색할 항목은? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
String condition = null;
switch (menuNo) {
case 1:
System.out.print("삭제할 게시글의 제목? ");
condition = "title='" + keyboard.nextLine() + "'";
break;
case 2:
System.out.print("삭제할 게시글의 내용? ");
condition = "contents='" + keyboard.nextLine() + "'";
break;
case 3:
System.out.print("삭제할 게시글의 번호? ");
condition = "board_id=" + keyboard.nextLine();
break;
default:
System.out.println("메뉴 번호가 옳지 않습니다.");
keyboard.close();
return;
}
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex03/f/mybatis-config.xml")).openSession(true);
// ${} 문법은 SQL에 코드를 사입할 때 사용한다.
// 잘 쓰면 매우 편리하다.
// => SQL 문을 한 개만 만들어 놓고
// 조건 변경하면서 다양한 방식으로 사용할 수 있다.
// => 즉 게시글 제목, 내용, 번호를 조건으로 삭제할 수 있는 SQL 문을 쉽게 만들 수 있다.
//
// 문제는 잘못된 방식으로 사용하면 위험하다.
// => 사용자의 입력 값을 정제하지 않고 그대로 SQL문에 삽입하면
// 해킹이 가능한 상태가 될 수 있어 매우 위험하다.
//
// 제목을 입력할 때 다음과 같이 입력해 보라!
// => a' or 't'='t
// => 사용자가 위와 같이 입력했다고 가정하면
// 실행할 SQL 문은 다음과 같다.
// delete from x_board
// where title='a' or 't'='t'
// 즉 x_board 테이블의 모든 데이터를 삭제하는 SQL 문이 만들어진다.
//
int count = sqlSession.delete("BoardMapper.delete2", condition);
System.out.println(count);
sqlSession.close();
keyboard.close();
}
}
결론!
- ${} 문법을 사용하지 말라는 것이 아니다.
- ${} 문법을 사용했을 때 여러 개의 SQL 문을 만들 필요가 없어 매우 편리해지는 경우가 있다.
즉 약간의 조건에 따라 SQL 문이 바뀌는 상황에서 ${} 문법은 매우 유용하다.
- 다만 SQL 삽입 공격이 불가능하도록 주의해서 사용해야 한다.
즉 사용자가 입력한 값이 SQL에 영향을 끼치지 않도록 해야 한다.
com.eomcs.mybatis.ex04.a
ex04/a/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- 제목으로 게시글 검색하기 -->
<select id="select1" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where title like concat('%', #{value}, '%')
order by board_id desc
</select>
<!-- 내용으로 게시글 검색하기 -->
<select id="select2" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where contents like concat('%', #{value}, '%')
order by board_id desc
</select>
<!-- 여러 SQL 문에 공통으로 포함되는 코드가 있다면 다음과 같이
별도의 sql 태그에 작성해 두고 사용하면 편리하다. -->
<sql id="sql1">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
</sql>
<sql id="sql2">
order by board_id desc
</sql>
<!-- 제목으로 게시글 검색하기 -->
<select id="select3" resultMap="BoardMap" parameterType="string">
<include refid="sql1"/>
where title like concat('%', #{value}, '%')
<include refid="sql2"/>
</select>
<!-- 내용으로 게시글 검색하기 -->
<select id="select4" resultMap="BoardMap" parameterType="string">
<include refid="sql1"/>
where contents like concat('%', #{value}, '%')
<include refid="sql2"/>
</select>
</mapper>
<sql> 태그 사용법 (사용 전)
package com.eomcs.mybatis.ex04.a;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
if (!(menuNo == 1 || menuNo == 2)) {
System.out.println("검색 항목 번호가 옳지 않습니다.");
keyboard.close();
return;
}
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/a/mybatis-config.xml")).openSession();
List<Board> boards = null;
if (menuNo == 1) {
boards = sqlSession.selectList("BoardMapper.select1", keyword);
} else if (menuNo == 2) {
boards = sqlSession.selectList("BoardMapper.select2", keyword);
}
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
<sql> 태그 사용법 (사용 후)
package com.eomcs.mybatis.ex04.a;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
if (!(menuNo == 1 || menuNo == 2)) {
System.out.println("검색 항목 번호가 옳지 않습니다.");
keyboard.close();
return;
}
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/a/mybatis-config.xml")).openSession();
List<Board> boards = null;
// 여러 SQL문에 공통들어 가는 코드가 있다면
// <sql> 태그를 사용하여 별도로 정의할 수 있다.
// <include> 태그를 사용하여 <sql> 태그의 값을 가져올 수 있다.
//
if (menuNo == 1) {
boards = sqlSession.selectList("BoardMapper.select3", keyword);
} else if (menuNo == 2) {
boards = sqlSession.selectList("BoardMapper.select4", keyword);
}
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
ex04/b/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- 제목으로 게시글 검색하기 -->
<select id="select1" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where title like concat('%', #{value}, '%')
order by board_id desc
</select>
<!-- 내용으로 게시글 검색하기 -->
<select id="select2" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where contents like concat('%', #{value}, '%')
order by board_id desc
</select>
<!-- if 태그를 사용하면 값의 유무에 따라 SQL 문을 제어할 수 있다. -->
<!-- 문법:
=> <if test="조건">
=> 조건은 true/false를 리턴하는 계산식이어야 한다.
=> 파라미터 타입이 자바 원시 타입, String, 래퍼 클래스의 경우
값을 꺼낼 때 프로퍼티 이름은 #{아무이름} 을 쓰면 된다.
-->
<select id="select3" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where
<if test="menuNo == 1">
title like concat('%', #{keyword}, '%')
</if>
<if test="menuNo == 2">
contents like concat('%', #{keyword}, '%')
</if>
order by board_id desc
</select>
<!-- 조건이 여러 개일 경우 if 태그 보다 choose 태그가 더 편리하다.
자바의 switch 문과 사용법이 비슷하다. -->
<select id="select4" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where
<choose>
<when test="menuNo == 1">
title like concat('%', #{keyword}, '%')
</when>
<when test="menuNo == 2">
contents like concat('%', #{keyword}, '%')
</when>
<otherwise>
1!=1
</otherwise>
</choose>
order by board_id desc
</select>
</mapper>
Dynamic SQL - if 태그 사용법(사용 전)
package com.eomcs.mybatis.ex04.b;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();
List<Board> boards = null;
// dynamic sql?
// => 조건에 따라 SQL이 변경되는 것.
// => mybatis는 이를 위해 조건문, 반복문 등을 다룰 수 있도록 특별한 태그를 제공한다.
//
// dynamic sql 사용 전:
// - 검색 항목 선택에 따라 SQL 문이 달라지기 때문에
// 다음과 같이 where 절의 일부분만 다른,
// SQL문을 여러 개 작성해야 한다.
// - 그리고 조건에 따라 실행할 SQL 문을 구분해서 호출해야 한다.
//
if (menuNo == 1) {
boards = sqlSession.selectList("BoardMapper.select1", keyword);
} else if (menuNo == 2) {
boards = sqlSession.selectList("BoardMapper.select2", keyword);
}
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - if 태그 사용법(사용 후)
package com.eomcs.mybatis.ex04.b;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();
// dynamic sql 사용 후:
// - if 태그를 사용하여 조건에 따라 다른 SQL 문을 만들 수 있다.
// - 이렇게 SQL 문이 고정되는 것이 아니라 변경될 수 있는 것을
// 'Dynamic SQL' 이라고 한다.
//
HashMap<String,Object> params = new HashMap<>();
params.put("menuNo", menuNo);
params.put("keyword", keyword);
// Dynamic SQL 을 사용하면 여러 개의 SQL 문을 만들 필요가 없다.
List<Board> boards = sqlSession.selectList("BoardMapper.select3", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - choose/when/otherwise 태그 사용법
package com.eomcs.mybatis.ex04.b;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam210 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/b/mybatis-config.xml")).openSession();
// 조건이 여러 개일 때는 if 태그 보다 choose 태그를 사용하는 것이
// SQL을 다루기 더 편하다.
//
HashMap<String,Object> params = new HashMap<>();
params.put("menuNo", menuNo);
params.put("keyword", keyword);
// Dynamic SQL 을 사용하면 여러 개의 SQL 문을 만들 필요가 없다.
List<Board> boards = sqlSession.selectList("BoardMapper.select4", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
ex04/c/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- 다음 SQL 문의 문제점은
조건에 일치하는 경우가 없을 때
where 다음에 놓이는 조건문이 없다는 것이다.
그래서 실행할 때 SQL문법 오류가 발생한다. -->
<select id="select0110" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where
<if test="menuNo == 1">
title like concat('%', #{keyword}, '%')
</if>
<if test="menuNo == 2">
contents like concat('%', #{keyword}, '%')
</if>
order by board_id desc
</select>
<select id="select0120" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
<where>
<if test="menuNo == 1">
title like concat('%', #{keyword}, '%')
</if>
<if test="menuNo == 2">
contents like concat('%', #{keyword}, '%')
</if>
</where>
order by board_id desc
</select>
<!-- where 절에 여러 개의 조건이 삽입될 때 문제점 -->
<select id="select0210" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where
<if test="title != null">
title like concat('%', #{title}, '%')
</if>
<if test="contents != null">
and contents like concat('%', #{contents}, '%')
</if>
order by board_id desc
</select>
<!-- where 태그를 사용하면,
1) 조건이 한 개도 없을 경우, where 절을 추가하지 않는다.
2) 조건 앞뒤에 and, or 연산자가 있을 경우, 자동으로 제거한다.
-->
<select id="select0220" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
<where>
<if test="title != null">
title like concat('%', #{title}, '%')
</if>
<if test="contents != null">
and contents like concat('%', #{contents}, '%')
</if>
</where>
order by board_id desc
</select>
<!-- <where> 태그 대신에 <trim> 태그를 사용하여
문장 앞뒤에 오는 OR 나 AND 를 제거할 수 있다.
-->
<select id="select0230" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
<trim prefix="where" prefixOverrides="or|and">
<if test="title != null">
title like concat('%', #{title}, '%')
</if>
<if test="contents != null">
and contents like concat('%', #{contents}, '%')
</if>
</trim>
order by board_id desc
</select>
<!-- 특정 조건이 있을 경우에만 select를 수행할 때,
1) 조건이 없으면 결과를 리턴하지 않는 방법?
다음과 같이 where 절에 기본 조건을 명시한다.
where
1!=1 <== 기본 조건. 예) 무조건 거짓이 되게 하기
-->
<select id="select0310" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where
1!=1
<if test="title != null">
or title like concat('%', #{title}, '%')
</if>
<if test="contents != null">
or contents like concat('%', #{contents}, '%')
</if>
order by board_id desc
</select>
</mapper>
Dynamic SQL - where 태그의 필요성
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// where 다음에 일치하는 조건이 없을 경우
// SQL 문법 오류가 발생한다.
// => 검색 항목의 번호를 1, 2가 아닌 다른 숫자를 입력한 후 테스트 해 보라!
//
HashMap<String,Object> params = new HashMap<>();
params.put("menuNo", menuNo);
params.put("keyword", keyword);
List<Board> boards = sqlSession.selectList("BoardMapper.select0110", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - where 태그 사용법
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색 항목:\n 1. 제목\n 2. 내용\n검색 항목? ");
int menuNo = Integer.parseInt(keyboard.nextLine());
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// <where> 태그 안에 놓이는 SQL이 없을 경우
// where 절은 삽입되지 않는다.
//
HashMap<String,Object> params = new HashMap<>();
params.put("menuNo", menuNo);
params.put("keyword", keyword);
List<Board> boards = sqlSession.selectList("BoardMapper.select0120", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - where 태그의 필요성 II
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0210 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String title = keyboard.nextLine();
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
String contents = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// where 절에 여러 개의 조건이 있을 경우 발생할 수 있는 문제점을 확인해 보자.
// 테스트 1)
// - 제목, 내용 모두 검색어를 입력한다.
// => 해당 제목과 내용을 포함하고 있는 게시글을 정상적으로 리턴한다.
// 테스트 2)
// - 제목만 입력한다.
// => where 다음에 title 컬럼의 조건을 검사하는 코드가 붙기 때문에
// 정상적으로 수행한다.
// 테스트 3)
// - 제목, 내용 모두 빈 문자열로 입력한다.
// => where 다음에 조건을 지정하는 SQL 문이 없기 때문에 SQL 문법 오류가 발생한다.
// 테스트 4)
// - 내용만 입력한다.
// => where 다음에 내용을 검사하는 코드가 붙는다.
// 문제는 제목을 검사하는 조건이 빠지는 바람에
// 내용을 검사하는 코드 앞에 and 가 남아 있어서 SQL 문법 오류가 발생한다.
/// select board_id, title, contents, created_date, view_count
// from x_board
// where and contents like concat('%', ?, '%')
// order by board_id desc
// 해결책)
// - <where> 태그를 사용하면
// 1. 조건이 비어 있을 때 where 절을 붙이기 않는다.
// 2. and, or 잔여물이 붙어 있을 때 자동으로 제거한다.
// - <trim> 태그를 사용하면
// 1. 제목이 빠진 후에 내용 조건을 검사하는 코드 앞에 and 가 붙는 것을 제거할 수 있다.
//
HashMap<String,Object> params = new HashMap<>();
if (title.length() > 0) {
params.put("title", title);
}
if (contents.length() > 0) {
params.put("contents", contents);
}
List<Board> boards = sqlSession.selectList("BoardMapper.select0210", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - where 태그 사용법 II
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0220 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String title = keyboard.nextLine();
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
String contents = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// <where> 태그를 사용하면
// 1) 조건이 비어 있을 때 where 절을 붙이기 않는다.
// 2) and, or 잔여물이 붙어 있을 때 자동으로 제거한다.
//
HashMap<String,Object> params = new HashMap<>();
if (title.length() > 0) {
params.put("title", title);
}
if (contents.length() > 0) {
params.put("contents", contents);
}
List<Board> boards = sqlSession.selectList("BoardMapper.select0220", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - trim 태그 사용법
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0230 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String title = keyboard.nextLine();
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
String contents = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// 내용만 입력 했을 때 문제점
// => 다음과 같이 where 다음에 내용을 검사하는 코드가 붙는다.
// 문제는 제목을 검사하는 조건이 빠지는 바람에
// 내용을 검사하는 코드 앞에 and 가 남아 있어서 SQL 문법 오류가 발생한다.
/// select board_id, title, contents, created_date, view_count
// from x_board
// where and contents like concat('%', ?, '%')
// order by board_id desc
// 해결책)
// - <where> 태그를 사용하면 된다.
// - <trim> 태그를 사용하여 쓸데없이 붙은 and 나 or 를 제거하면 된다.
//
HashMap<String,Object> params = new HashMap<>();
if (title.length() > 0) {
params.put("title", title);
}
if (contents.length() > 0) {
params.put("contents", contents);
}
List<Board> boards = sqlSession.selectList("BoardMapper.select0230", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - 무조건 false가 되는 조건을 포함해야 하는 경우
package com.eomcs.mybatis.ex04.c;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0310 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String title = keyboard.nextLine();
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
String contents = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/c/mybatis-config.xml")).openSession();
// 사례1)
// where
// <if test="title != null">
// title like concat('%', #{title}, '%')
// </if>
// <if test="contents != null">
// or contents like concat('%', #{contents}, '%')
// </if>
//
// - 위 where 절의 경우
// => 검색어로 제목을 입력하면 해당 검색어를 제목으로 포함하는 게시글을 결과에 포함한다.
// => 검색어로 내용을 입력하면 해당 검색어를 내용으로 포함하는 게시글을 결과에 포함한다.
// => 만약 둘 다 입력하지 않으면 where 절 문법 오류가 발생한다.
//
// 요구사항
// - 검색어를 모두 입력하지 않았을 때 SQL 오류를 발생시키지 않고 빈 결과를 리턴하게 하는 방법은?
// => where 절에 무조건 false를 리턴하는 조건을 추가하면 된다.
//
HashMap<String,Object> params = new HashMap<>();
if (title.length() > 0) {
params.put("title", title);
}
if (contents.length() > 0) {
params.put("contents", contents);
}
List<Board> boards = sqlSession.selectList("BoardMapper.select0310", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
ex04/d/BoardMapper.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="BoardMapper">
<!-- udpate를 실행할 때
값을 변경하는 컬럼에 대해서만 update를 수행하게 할 수 있다.
<set>과 <if> 태그를 조합하면 된다.
-->
<update id="update1" parameterType="board">
update x_board set
<if test="title != null">
title=#{title},
</if>
<if test="content != null">
contents=#{content}
</if>
where board_id=#{no}
</update>
<!-- set 태그는 컬럼 값을 변경하는 문장 앞뒤에 쓸데없이 붙어 있는 콤마(,)를 제거해 준다. -->
<update id="update2" parameterType="board">
update x_board
<set>
<if test="title != null">
title=#{title},
</if>
<if test="content != null">
contents=#{content}
</if>
</set>
where board_id=#{no}
</update>
</mapper>
Dynamic SQL - update 문에 if 태그의 활용
package com.eomcs.mybatis.ex04.d;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
Board board = new Board();
// 게시글 번호 입력 받기
System.out.print("변경할 게시글의 번호? ");
board.setNo(Integer.parseInt(keyboard.nextLine()));
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String input = keyboard.nextLine();
if (input.length() > 0) {
board.setTitle(input);
}
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
input = keyboard.nextLine();
if (input.length() > 0) {
board.setContent(input);
}
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/d/mybatis-config.xml")).openSession(true);
// if 태그를 활용하면 전체 컬럼이 아니라 일부 항목만 변경하는 SQL을 만들 수 있다.
// 테스트 1)
// - 제목, 내용 모두 변경하기
// 텍스트 2)
// - 내용만 변경하기
// 테스트 3)
// - 제목만 변경하기
// - set 다음에 오는 문장 뒤에 콤마(,)가 붙기 때문에 SQL 문법 오류가 발생한다.
// update x_board set
// title=?, <=== 문장 뒤에 콤마(,)가 붙어 있다.
// where board_id=?
// - 해결책?
// <set> 태그를 사용하라!
//
int count = sqlSession.update("BoardMapper.update1", board);
System.out.println(count);
sqlSession.close();
}
}
Dynamic SQL - set 태그의 필요성
package com.eomcs.mybatis.ex04.d;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
Board board = new Board();
// 게시글 번호 입력 받기
System.out.print("변경할 게시글의 번호? ");
board.setNo(Integer.parseInt(keyboard.nextLine()));
System.out.print("제목?(건너 뛰기: 빈 문자열) ");
String input = keyboard.nextLine();
if (input.length() > 0) {
board.setTitle(input);
}
System.out.print("내용?(건너 뛰기: 빈 문자열) ");
input = keyboard.nextLine();
if (input.length() > 0) {
board.setContent(input);
}
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/d/mybatis-config.xml")).openSession(true);
// 다음과 같이 set 문장 앞뒤에 쓸데없이 콤마(,)가 붙을 경우 자동으로 제거하는 방법?
// update x_board set
// title=?, <=== 문장 뒤에 콤마(,)가 붙어 있다.
// where board_id=?
//
// - <set> 태그를 사용하라!
//
int count = sqlSession.update("BoardMapper.update2", board);
System.out.println(count);
sqlSession.close();
}
}
ex04/e/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- foreach 를 사용하지 않으면 값의 개수 만큼 SQL 코드를 작성해야 한다. -->
<select id="select1" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
<where> 1=0
<if test="keyword1 != ''">
or title like concat('%', #{keyword1}, '%')
</if>
<if test="keyword2 != ''">
or title like concat('%', #{keyword2}, '%')
</if>
<if test="keyword3 != ''">
or title like concat('%', #{keyword3}, '%')
</if>
</where>
order by board_id desc
</select>
<!-- foreach를 사용하면 값 개수 만큼 SQL 코드를 반복적으로 생성할 수 있다. -->
<select id="select2" resultMap="BoardMap" parameterType="map">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
<where> 1=0
<foreach collection="keywords" item="keyword">
or title like concat('%', #{keyword}, '%')
</foreach>
</where>
order by board_id desc
</select>
</mapper>
Dynamic SQL - foreach 태그의 필요성
package com.eomcs.mybatis.ex04.e;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색어1? ");
String keyword1 = keyboard.nextLine();
System.out.print("검색어2? ");
String keyword2 = keyboard.nextLine();
System.out.print("검색어3? ");
String keyword3 = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/e/mybatis-config.xml")).openSession();
// 여러 개의 검색어로 데이터를 찾을 때
// => 최대 3개의 검색어로 제한하는 경우
HashMap<String,Object> params = new HashMap<>();
params.put("keyword1", keyword1);
params.put("keyword2", keyword2);
params.put("keyword3", keyword3);
// if 태그를 사용하는 방식의 한계는
// - 조건의 개수가 고정된다.
// - 즉 if 태그의 개수만큼만 조건을 검사할 수 있다.
// - 조건 개수를 늘리려면 if 태그를 추가해야 한다.
// 해결책?
// - foreach 태그를 사용하라!
//
List<Board> boards = sqlSession.selectList("BoardMapper.select1", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
Dynamic SQL - foreach 태그의 활용
package com.eomcs.mybatis.ex04.e;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
ArrayList<String> keywords = new ArrayList<>();
while (true) {
System.out.print("검색어?(빈 문자열: 입력 완료!) ");
String keyword = keyboard.nextLine();
if (keyword.length() == 0) {
break;
}
keywords.add(keyword);
}
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/e/mybatis-config.xml")).openSession();
// 값을 여러 개 넘길 때는 항상 맵에 담아서 넘겨라!
HashMap<String,Object> params = new HashMap<>();
params.put("keywords", keywords);
// foreach 태그를 사용하면
// - 값의 개수 만큼 SQL 코드를 반복해서 생성할 수 있다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.select2", params);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
ex04/f/BoardMapper.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="BoardMapper">
<!-- 게시글의 첨부파일 입력 -->
<insert id="insert1" parameterType="attachFile">
insert into x_board_file(file_path, board_id)
values(#{filePath}, #{boardNo})
</insert>
<!-- foreach 태그를 사용하여 여러 개의 첨부파일을 한 번에 입력하기 -->
<insert id="insert2" parameterType="map">
insert into x_board_file(file_path, board_id)
values
<foreach collection="files" item="attachFile" separator="," >
(#{attachFile.filePath}, #{boardNo})
</foreach>
</insert>
<!-- 위의 코드는 다음의 자바 코드와 같은 의미다.
ArrayList<AttachFile> files = (ArrayList<AttachFile>)map.get("files");
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("insert into x_board_file(file_path, board_id) ");
strBuilder.append("values ");
int count = 0;
for (AttachFile attachFile : files) {
if (count > 0) {
strBuilder.append(",");
}
strBuilder.append("(" + attachFile.getFilePath() + ", " + map.get("boardNo") + ")");
}
-->
</mapper>
insert 문에 foreach를 사용할 필요성
package com.eomcs.mybatis.ex04.f;
import java.util.ArrayList;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("게시글 번호? ");
int boardNo = Integer.parseInt(keyboard.nextLine());
ArrayList<AttachFile> files = new ArrayList<>();
while (true) {
System.out.print("첨부파일?(빈 문자열: 입력 종료) ");
String input = keyboard.nextLine();
if (input.length() == 0) {
break;
}
files.add(new AttachFile(boardNo, input));
}
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/f/mybatis-config.xml")).openSession(true);
// 게시글의 첨부파일을 저장하기
// - List 에 보관된 개수만큼 반복해서 insert를 실행한다.
// - SQL을 실행한다는 것은 DBMS에 SQL 실행을 요청한다는 의미다.
// - 여러 번 실행한다는 것은 DBMS에 여러 번 요청한다는 의미다.
// - 즉 네트워크 사용이 증가한다.
//
// 여러 개의 데이터 입력을 한 번에 처리하는 방법은 없을까?
// - insert 를 한 번만 요청하면 된다.
//
int count = 0;
for (AttachFile file : files) {
count += sqlSession.insert("BoardMapper.insert1", file);
}
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
sqlSession.close();
}
}
package com.eomcs.mybatis.vo;
public class AttachFile {
int fileNo;
String filePath;
int boardNo;
public AttachFile() {
}
public AttachFile(int boardNo, String filePath) {
this.boardNo = boardNo;
this.filePath = filePath;
}
public int getFileNo() {
return fileNo;
}
public void setFileNo(int fileNo) {
this.fileNo = fileNo;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public int getBoardNo() {
return boardNo;
}
public void setBoardNo(int boardNo) {
this.boardNo = boardNo;
}
}
insert 문에 foreach를 사용하기
package com.eomcs.mybatis.ex04.f;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("게시글 번호? ");
int boardNo = Integer.parseInt(keyboard.nextLine());
ArrayList<AttachFile> files = new ArrayList<>();
while (true) {
System.out.print("첨부파일?(빈 문자열: 입력 종료) ");
String input = keyboard.nextLine();
if (input.length() == 0) {
break;
}
files.add(new AttachFile(boardNo, input));
}
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/f/mybatis-config.xml")).openSession(true);
// insert 문을 만들 때 사용할 값을 Map 에 담는다.
HashMap<String,Object> params = new HashMap<>();
params.put("boardNo", boardNo);
params.put("files", files);
// 한 번에 여러 개의 값을 insert 하는 방법?
// - 다음과 같이 여러 개의 값을 한 번에 저장하는 insert 문을 생성한다.
// insert into x_board_file(file_path, board_id)
// values (파일명, 게시글번호),(파일명, 게시글번호),(파일명, 게시글번호),...
// - 위와 같이 만든 insert 문장 한 개를 실행한다.
// 즉 이것은 DBMS에 한 번만 요청한다는 의미다.
//
int count = sqlSession.insert("BoardMapper.insert2", params);
System.out.printf("%d 개의 데이터를 입력 했음!\n", count);
sqlSession.close();
}
}
ex04/g/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<!-- 검색어로 게시글 찾기 like 연산자 사용 -->
<select id="select1" resultMap="BoardMap" parameterType="string">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where title like concat('%', #{keyword}, '%')
</select>
<!-- like 연산자에서 사용할 값을 bind 태그로 준비하기
문법:
<bind
name="변수명"
value="변수에 저장할 값을 만드는 표현식"/>
_parameter:
=> parameterType 으로 넘어 오는 값을 가리키는 변수명
변수 사용법:
=> 이전에 파라미터의 값을 사용하듯이 #{변수명} 문법을 사용하면 된다.
-->
<select id="select2" resultMap="BoardMap" parameterType="string">
<bind name="pattern1" value="'%' + _parameter + '%'"/>
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where title like #{pattern1}
</select>
</mapper>
bind 태그 사용법 - 사용 전
package com.eomcs.mybatis.ex04.g;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/g/mybatis-config.xml")).openSession();
List<Board> boards = sqlSession.selectList("BoardMapper.select1", keyword);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
bind 태그 사용법 - 사용 후
package com.eomcs.mybatis.ex04.g;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("검색어? ");
String keyword = keyboard.nextLine();
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex04/g/mybatis-config.xml")).openSession();
// 메서드를 실행할 때 넘겨준 값으로
// mybatis 는 <bind> 태그를 사용하여 like 연산에 사용할 값을 준비한다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.select2", keyword);
for (Board b : boards) {
System.out.printf("%d,%s,%s,%s,%d\n",
b.getNo(),
b.getTitle(),
b.getContent(),
b.getRegisteredDate(),
b.getViewCount());
}
sqlSession.close();
}
}
com.eomcs.mybatis.ex05
ex05/a/BoardMapper.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="BoardMapper">
<resultMap type="Board" id="BoardMap">
<id column="board_id" property="no"/>
<!--
<result column="title" property="title"/>
-->
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
</resultMap>
<resultMap type="AttachFile" id="AttachFileMap">
<id column="board_file_id" property="fileNo"/>
<result column="file_path" property="filePath"/>
<result column="board_id" property="boardNo"/>
</resultMap>
<resultMap type="Board" id="BoardWithAttachFilesMap">
<id column="board_id" property="no"/>
<!-- 테이블 조인을 수행한 경우 컬럼 이름과 프로퍼티 이름이 같더라도 생략하면 안된다. -->
<result column="title" property="title"/>
<result column="contents" property="content"/>
<result column="created_date" property="registeredDate"/>
<result column="view_count" property="viewCount"/>
<collection property="attachFiles" ofType="AttachFile">
<id column="board_file_id" property="fileNo"/>
<result column="file_path" property="filePath"/>
<!-- 조인한 자식 테이블의 데이터가 없으면 AttachFile 객체를 생성하지 않는다.
size 가 0인 List 객체를 리턴할 것이다.
주의!
다음과 같이 자식 테이블의 값을 담을 컬럼을 지정할 때
그 컬럼의 값이 NULL 아니라면
자식 테이블의 데이터가 없더라도 그 값을 담기 위해 자바 객체는 무조건 생성된다.
그래서 최소 size가 1인 List 객체를 리턴한다.
<result column="board_id" property="boardNo"/>
-->
</collection>
</resultMap>
<select id="selectBoard" resultMap="BoardMap" parameterType="int">
select
board_id,
title,
contents,
created_date,
view_count
from x_board
where board_id=#{no}
</select>
<select id="selectFiles" resultMap="AttachFileMap" parameterType="int">
select
board_file_id,
file_path,
board_id
from x_board_file
where board_id=#{no}
</select>
<select id="selectBoard2" resultMap="BoardWithAttachFilesMap" parameterType="int">
select
b.board_id,
b.title,
b.contents,
b.created_date,
b.view_count,
bf.board_file_id,
bf.file_path
from x_board b
left outer join x_board_file bf on b.board_id=bf.board_id
<if test="no != null">
where b.board_id=#{no}
</if>
</select>
</mapper>
조인 데이터 가져오기 - 각 테이블의 데이터를 별도로 가져오기
package com.eomcs.mybatis.ex05.a;
import java.util.List;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;
public class Exam0110 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("게시글 번호? ");
int no = Integer.parseInt(keyboard.nextLine());
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex05/a/mybatis-config.xml")).openSession();
Board b = sqlSession.selectOne("BoardMapper.selectBoard", no);
System.out.println("[게시글 상세보기]");
System.out.printf("번호: %d\n", b.getNo());
System.out.printf("제목: %s\n", b.getTitle());
System.out.printf("내용: %s\n", b.getContent());
System.out.printf("등록일: %s\n", b.getRegisteredDate());
System.out.printf("조회수: %d\n", b.getViewCount());
System.out.println("첨부파일:");
List<AttachFile> files = sqlSession.selectList("BoardMapper.selectFiles", b.getNo());
for (AttachFile f : files) {
System.out.printf(" %d - %s\n", f.getFileNo(), f.getFilePath());
}
sqlSession.close();
}
}
조인 데이터 가져오기 - 한 번의 질의로 Board 객체에 AttachFile 객체의 목록을 담아서 리턴 받기
package com.eomcs.mybatis.ex05.a;
import java.util.Scanner;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;
public class Exam0120 {
public static void main(String[] args) throws Exception {
Scanner keyboard = new Scanner(System.in);
System.out.print("게시글 번호? ");
int no = Integer.parseInt(keyboard.nextLine());
keyboard.close();
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex05/a/mybatis-config.xml")).openSession();
// 게시글 데이터를 가져올 때 첨부 파일 데이터도 포함해서 가져올 수 있다.
// => 테이블 조인 기법을 사용한다.
// => 도메인 객체의 포함 관계를 활용한다.
//
Board b = sqlSession.selectOne("BoardMapper.selectBoard2", no);
System.out.println("[게시글 상세보기]");
System.out.printf("번호: %d\n", b.getNo());
System.out.printf("제목: %s\n", b.getTitle());
System.out.printf("내용: %s\n", b.getContent());
System.out.printf("등록일: %s\n", b.getRegisteredDate());
System.out.printf("조회수: %d\n", b.getViewCount());
System.out.println("첨부파일:");
for (AttachFile f : b.getAttachFiles()) {
System.out.printf(" %d - %s\n", f.getFileNo(), f.getFilePath());
}
sqlSession.close();
}
}
조인 데이터 가져오기 - 여러 개의 조인 데이터 가져오기
package com.eomcs.mybatis.ex05.a;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.eomcs.mybatis.vo.AttachFile;
import com.eomcs.mybatis.vo.Board;
public class Exam0130 {
public static void main(String[] args) throws Exception {
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(
"com/eomcs/mybatis/ex05/a/mybatis-config.xml")).openSession();
// 게시글 데이터를 가져올 때 첨부 파일 데이터도 포함해서 가져올 수 있다.
// => 테이블 조인 기법을 사용한다.
// => 도메인 객체의 포함 관계를 활용한다.
//
List<Board> boards = sqlSession.selectList("BoardMapper.selectBoard2");
for (Board b : boards) {
System.out.printf("번호: %d\n", b.getNo());
System.out.printf("제목: %s\n", b.getTitle());
System.out.printf("내용: %s\n", b.getContent());
System.out.printf("등록일: %s\n", b.getRegisteredDate());
System.out.printf("조회수: %d\n", b.getViewCount());
System.out.printf("첨부파일(%d):\n", b.getAttachFiles().size());
// if (b.getAttachFiles().size() == 1 &&
// b.getAttachFiles().get(0).getFileNo() == 0) {
// System.out.println(" 첨부파일이 없습니다!");
// continue;
// }
for (AttachFile f : b.getAttachFiles()) {
System.out.printf(" %d - %s\n", f.getFileNo(), f.getFilePath());
}
System.out.println("-----------------------------------------------------");
}
sqlSession.close();
}
}
'네이버클라우드 AIaaS 개발자 양성과정 1기 > DBMS, SQL, JDBC, Servlet' 카테고리의 다른 글
[비트캠프] 73일차(15주차5일) - Servlet(URL 절대 경로와 상대 경로) (1) | 2023.02.17 |
---|---|
[비트캠프] 72일차(15주차4일) - Mybatis(톰캣 서버) (0) | 2023.02.16 |
[비트캠프] 71일차(15주차3일) - JDBC(MyBatis), myapp-42~43(SqlSession, 프록시 패턴) (0) | 2023.02.15 |
[비트캠프] 70일차(15주차2일) - JDBC: myapp-39~42중간(커넥션 풀, PreparedStatement, Mybatis) (0) | 2023.02.14 |
[비트캠프] 69일차(15주차1일) - JDBC: myapp-38 (0) | 2023.02.13 |