MyBatis
MyBatis란?
MyBatis란 객체지향 언어인 자바의 관계형 데이터 베이스 프로그래밍을 좀더 쉽게 할 수 있도록 도와주는 프레임워크입니다.
Framwork
뼈대나 근간을 이루는 코드들의 묶음
프로그램의 기본 흐름이나 구조를 미리 정해놓고 이 구조에 자신의 코드를 추가하는 방식으로 개발할 수 있도록 하는 프로그래밍의 기본 틀을 의미.
개발에 필요한 구조가 사전에 제공(대체로 다운로드 받을 수 있다)되고, 여기에 필요한 부분을 개발자가 구현해서 조립하는 형태로 개방이 진행된다.
Framwork를 사용할 경우 장점
- 개발 기간을 단축할 수 있다
- 팀 안에서 개인의 능력 차이를 극복하고 일정한 품질을 보장할 수 있다.
#01. 환경설정
1) 라이브러리 설정
다음의 항목들을 Eclipse의 Java Build Path에 설정한다.
2) 설정파일 구성
study.java.mybatis 패키지를 생성하고 그 안에 mybatis_config.xml파일을 생성한다.
패키지 이름과 파일명은 임의로 변경 가능
mybatis_config.xml
https://mybatis.org/mybatis-3/ko/getting-started.html에서 설정파일의 기본 원형을 가져와 생성한 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> <property name="hostname" value="호스트이름" /> <property name="portnumber" value="포트번호" /> <property name="database" value="DB이름" /> <property name="username" value="사용자계정" /> <property name="password" value="비밀번호" /> </properties> <!-- MySQL 접속 객체 구성 --> <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="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
before
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration= <configuration>= </configuration>
after
${dirver}라고 된 위치에 MySQL JDBC 8의 driver 이름인 com.mysql.cj.jdbc.Driver을 적용한다.
&{url}로 위치는 아래와 같은 형식의 접속 문자열을 구성해야 한다.
jdbc:mysql://localhost:3306/myschool?characterEncoding=UTF8&serverTimezone=UTC
localhost(host이름)
,3306(포트번호)
,myschool(db이름)
을 각각 별도의 변수로 사용하기 위해 다음과 같이 URL을 구성 jdbc:mysql://${hostname}:${portnumber}/${database}?characterEncoding=UTF8&serverTimezone=UTC
<mappers>
태그에 속한 항목을 일단 삭제한다.#02. 데이터 조회 결과가 저장될 자료구조 정의
study.java.model패키지를 추가하고 그 안에 테이블단위 혹은 Join문이 구성되는 단위마다 Beans클래스를 정의한다.
MyBatis를 위한 클래스에서는 생성자를 정의할 필요가 없다. 값의 할당은 setter 메서드를 사용한다.
packege study.java.model; public class Department { private int deptno; private String dname; private String loc; /** getter,setter, toString정의 */ // 강사님은 말하셨지 겟터셋터 투스트링 안해도 된다고 }
Lombok.jar 다운로드
Lombok.jar파일을 다운로드 받고 빌드패스 설정 후 Lombok.jar파일을 열어 이클립스 실행파일의 위치를 넣은 후 Install 버튼 클릭 이클립스 종료후 재실행
Lombok.jar파일 설정 완료
테이블 멤버변수 조회 개꿀팁
테이블안의 컬럼 조회
SELECT concat('private String', LOWER(COLUMN_NAME), ';') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'student';
student테이블의 멤버변수 조회
SQL에서 실행해야한다.
select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'student';
데이터베이스 이름을 따로 넣어 조회
select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA= 'myschool' AND TABLE_NAME = 'student';
+---------------------------------------------------------------------------------------+ | concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') | +---------------------------------------------------------------------------------------+ | private int studno; | | private String name; | | private String userid; | | private int grade; | | private String idnum; | | private String birthdate; | | private String tel; | | private int height; | | private int weight; | | private int deptno; | | private int profno; | +---------------------------------------------------------------------------------------+
교수테이블 멤버변수 조회
select concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA= 'myschool' AND TABLE_NAME = 'professor'; -------------------------------------------------- +---------------------------------------------------------------------------------------+ | concat('private ', if(DATA_TYPE = 'int', 'int ', 'String '), LOWER(COLUMN_NAME), ';') | +---------------------------------------------------------------------------------------+ | private int profno; | | private String name; | | private String userid; | | private String position; | | private int sal; | | private String hiredate; | | private int comm; | | private int deptno; | +---------------------------------------------------------------------------------------+
03. Mapper XML 정의
1) mybatis_config.xml 파일에 생성할 Mapper 경로 정의
<mappers>
태그 안에 생성할 파일의 경로를 명시해야 한다.<mappers> <mapper resource="study/java/mybatis/mappers/DepartmentMapper.xml" /> </mappers>mappers>
2) 명시한 Mapper 파일 생성
study.java.mybatis.mappers 패키지를 만들고 그 안에 Beans이름Mapper.xml형식으로 파일을 생성한다.
DepartmentMapper.xml
아래의 Mapper 원형 구문을 기본형으로 삼아 사용하되 구현하고자 하는 SQL문의 성격에 따라 추가적으로
<select>
,<insert>
,<update>
,<delete>
태그를 추가할 수 있다.{Beans}라고 명시한 부분은 사용하고자 하는 클래스 이름으로 수정하세요
각각의 태그가 하나의 DAO 메서드 역할을 하고 id속성값이 메서드 이름이 된다.
SQL문 안에서 parameterType으로 설정된 객체의 멤버변수를 통해 getter 메서드를 호출할 수 있다.
SELECT deptno, dname, loc FROM department WHERE deptno=#{deptno}
Mapper 원형
<?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="{Beans}Mapper"> // Interface나 클래스이름 <!-- Beans 클래스의 객체이름(id)과 클래스이름(type)을 명시한다. --> <resultMap id="SELECT결과가 저장될 객체이름" type="{Beans}의 패키지.클래스이름"> <!-- Beans의 멤버변수(property)이름과 대상 테이블의 컬럼(column)을 연결한다. --> <result property="{Beans}의 멤버변수1" column="연결될 테이블컬럼1" /> <result property="{Beans}의 멤버변수2" column="연결될 테이블컬럼2" /> <result property="{Beans}의 멤버변수3" column="연결될 테이블컬럼3" /> </resultMap> <!-- 단일행 조회를 위한 기능 정의 --> <select id="selectItem" parameterType="{Beans}의 패키지.클래스이름" // 파라미터타입은 무조건 빈즈의 풀네임 resultMap="<resultMap>에서 정의한 SELECT결과가 저장될 객체이름"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </select> <!-- 다중행 조회를 위한 기능 정의 --> <select id="selectList" parameterType="{Beans}의 패키지.클래스이름" resultMap="<resultMap>에서 정의한 SELECT결과가 저장될 객체이름"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </select> <!-- 데이터 수 조회를 위한 기능 정의 --> <select id="selectCount" parameterType="{Beans}의 패키지.클래스이름" resultType="int"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </select> <!-- 데이터 저장을 위한 기능 정의 --> <insert id="insertItem" parameterType="{Beans}의 패키지.클래스이름" useGeneratedKeys="true" keyProperty="테이블의 PK컬럼과 맵핑되는 JavaBeans의 멤버변수이름"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </insert> <!-- 데이터 삭제를 위한 기능 정의 --> <delete id="deleteItem" parameterType="{Beans}의 패키지.클래스이름"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </delete> <!-- 데이터 갱신을 위한 기능 정의 --> <update id="updateItem" parameterType="{Beans}의 패키지.클래스이름"> <!-- 이 안에서 처리할 SQL문을 명시한다. --> </update> </mapper>
트랜젝션
하나의 프로그램에서 수행되는 여러개의 SQL문들
에러코드 예시
- DepartmentMapper의 parameterType의 파일주소가 잘못 표기
Exception in thread "main" java.lang.ExceptionInInitializerError at DepartmentSelectOne.main(DepartmentSelectOne.java:9) Caused by: org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in study/java/mybatis/mappers/DepartmentMapper.xml ### The error occurred while processing mapper_resultMap[departmentMap] ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'. Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:52) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:36) at study.java.mybatis.MyBatisConnectionFactory.<clinit>(MyBatisConnectionFactory.java:29) ... 1 more Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'. Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:50) ... 3 more Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The XML location is 'study/java/mybatis/mappers/DepartmentMapper.xml'. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'. Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:122) at org.apache.ibatis.builder.xml.XMLMapperBuilder.parse(XMLMapperBuilder.java:94) at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:374) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119) ... 5 more Caused by: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'. Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:118) at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:76) at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:137) at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:130) at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:120) ... 8 more Caused by: org.apache.ibatis.type.TypeException: Could not resolve type alias 'study.java.model.Departent'. Cause: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:120) at org.apache.ibatis.builder.BaseBuilder.resolveAlias(BaseBuilder.java:149) at org.apache.ibatis.builder.BaseBuilder.resolveClass(BaseBuilder.java:116) ... 12 more Caused by: java.lang.ClassNotFoundException: Cannot find class: study.java.model.Departent at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:200) at org.apache.ibatis.io.ClassLoaderWrapper.classForName(ClassLoaderWrapper.java:89) at org.apache.ibatis.io.Resources.classForName(Resources.java:261) at org.apache.ibatis.type.TypeAliasRegistry.resolveAlias(TypeAliasRegistry.java:116) ... 14 more
- SelectList 메인문의 데이터 조회값 오타
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList ### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) at DepartmentSelectList.main(DepartmentSelectList.java:15) Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for DepartmentMappers.selectList at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:964) at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:755) at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:748) at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:146) ... 2 more
1.
<!-- 데이터 저장을 위한 기능 정의 --> <insert id="insertItem" parameterType="study.java.model.Department" useGeneratedKeys="true" keyProperty="deptno"> INSERT INTO department ( dname, loc // <-- "," 미입력과 오타 ) VALUES ( #{dname}, #{loc} ); </insert>
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error updating database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; ( danmem loc ) VALUES ( 'JAVA학과', 'JAVA관' ' at line 1 ### The error may exist in study/java/mybatis/mappers/DepartmentMapper.xml ### The error may involve DepartmentMapper.insertItem-Inline ### The error occurred while setting parameters ### SQL: INSERT INTO department; ( danmem loc ) VALUES ( ?, ? ); ### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; ( danmem loc ) VALUES ( 'JAVA학과', 'JAVA관' ' at line 1 at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:199) at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184) at DepartmentInsert.main(DepartmentInsert.java:17) Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; ( danmem loc ) VALUES ( 'JAVA학과', 'JAVA관' ' at line 1 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:370) at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47) at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74) at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50) at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117) at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197) ... 2 more