Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
-
Upload
donghyeok-kang -
Category
Software
-
view
674 -
download
7
Transcript of Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자
![Page 1: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/1.jpg)
Java Annotation과 MyBatis로나만의 ORM Framework을 만들어보자
2011 JCO 11th Conference | Session ${track_#}-${session_#} | Javacommunity.Org
강동혁 (한솔헬스케어)[email protected]: 20110612
![Page 2: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/2.jpg)
하기 싫은 일
Class.forName("com.mysql.jdbc.Driver");Connection c = DriverManager.getConnection();PreparedStatement stmt = c.prepareStatement
("select title, year_made from movies "+ "where year_made >= ?"+ " and year_made < ?");
for(int decadeStart = 1920; decadeStart < 2000; decadeStart += 10){stmt.setInt(1, decadeStart);stmt.setInt(2, decadeStart + 10);ResultSet rs = stmt.executeQuery();while(rs.next()){System.out.println(rs.getString(1) + " (" + rs.getInt(2) + ")");
}}
2
![Page 3: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/3.jpg)
귀찮은 일
<insert id="insertDoctor" parameterType="domain.Doctor">insert into Doctor (id,username,password,email,bio)values (#{id},#{username},#{password},#{email},#{bio})
</insert><update id="updateDoctor" parameterType="domain.Doctor">
update Doctor setusername = #{username}, password = #{password},email = #{email}, bio = #{bio}
where id = #{id}</update><delete id="deleteDoctor” parameterType="int">
delete from Doctor where id = #{id}</delete><select id="selectDoctor" resultType="domain.Doctor">
select * from Doctor</select>
3
![Page 4: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/4.jpg)
머리 아픈 일
<hibernate-mapping>
<class name="hello.Message“ table="MESSAGES">
<id name="id" column="MESSAGE_ID">
<generator class="increment"/>
</id>
<property name="text" column="MESSAGE_TEXT"/>
<many-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/>
</class>
</hibernate-mapping>
SELECT new list(mother, offspr, mate.name)
FROM DomesticCat AS mother
INNER JOIN mother.mate AS mate
LEFT OUTER JOIN mother.kittens AS offspr4
![Page 5: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/5.jpg)
하고 싶은 일
• SQL 작성 최소화
• Object oriented programming
• 로직에 집중
• 단순한 설정 - 쉽고, 직관적
• 학습의 최소화
5
![Page 6: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/6.jpg)
ORM? Hibernate?
6
![Page 7: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/7.jpg)
Hibernate + MyBatis?
7
![Page 8: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/8.jpg)
고려해야 할 점
• 설정
– object, relation 매핑
• SQL 생성
– object 를 SQL 의 파라미터로 전달
– SQL 결과를 object 로 리턴
8
![Page 9: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/9.jpg)
구현 전략
• object 와 relation 의 1:1 매핑 구현– MyBatis 를 이용하여 기본적인 insert, update,
delete, select 문을 runtime 자동 생성
– 생성된 SQL문을 MyBatis SQL repository 에저장
– Association 은 다루지 않음
– Join, subquery 구문은 MyBatis로 처리
• 설정은 Java Annotation 사용
• 일단 MySQL 먼저
9
![Page 10: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/10.jpg)
Java Annotation
• 자바 5.0 에서 소개• 자바 소스 코드에 추가되는 문법적인 메타데이터• 클래스, 메소드, 변수, 파라미터, 패키지에 첨언하
여 컴파일러의 의해 .class 파일에 포함되어 컴파일혹은 런타임 시 이용
• 번거로운 설정 작업들과 반복적인 코드를 줄여줌
• Built-in Annotations– @Override, @Deprecated, @SupressWarnings
• Custom Annotations– @Controller, @Service, @Entity, @Column
10
![Page 11: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/11.jpg)
Custom Annotation
• @interface 선언public @interface MyAnnotation {
String value();}
• Annotation 추가import MyAnnotation@MyAnnotation(value=“my annotation”)public void myMethod(int arg) {
// do something}
11
![Page 12: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/12.jpg)
Annotation API
• Class 와 Field
– getAnnotation(Class<A> annotationClass)특정 타입에 대한 annotation 을 리턴
– getAnnotations()모든 타입의 annotation 을 리턴
– isAnnotationPresent(Class annotationClass)특정 타입에 대한 annotation 이 존재하면true 리턴
12
![Page 13: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/13.jpg)
MyBatis
• 구) iBatis
• SQL문과 객체를 매핑
• SQL문을 XML 파일에 저장
• JDBC 코드 제거
13
출처) www.mybatis.org
![Page 14: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/14.jpg)
MyBatis 예제
• Mapped Statement<mapper namespace="org.mybatis.example.HospitalMapper">
<select id="selectHospital" parameterType="int" resultType="Hospital">
select * from Hospital where id = #{id}</select>
</mapper>
• Java DAO codepublic interface HospitalMapper {
public Hospital selectHospital(int id);}HospitalMapper mapper = session.getMapper(HospitalMapper.class);Hospital hospital = mapper.selectHospital(101);
14
![Page 15: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/15.jpg)
순서
1. Table 생성2. Annotation 정의3. Mapping class 생성4. EntityManager 작성 – CRUD interface5. SQL Generation 클래스 작성
– InsertSqlSource– UpdateSqlSource– DeleteSqlSource– SelectOneSqlSource– SelectListSqlSource
15
![Page 16: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/16.jpg)
1. Table 생성
Create table hospital (
hospitalid INT NOT NULL
PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30),
regdttm DATETIME
)
16
![Page 17: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/17.jpg)
2. Annotation 정의
public @interface Table {
String value() default "";
}
public @interface Column {
String name() default "";
boolean primaryKey() default false;
boolean autoIncrement() default false;
}
17
![Page 18: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/18.jpg)
3. Mapping Class
@Table(“hospital”)Public class Hospital {
@Column(primaryKey=true,autoIncrement=true)
private Integer hospitalid;@Column private String name;@Column(name=“regdttm”)
private Date regdttm;}
18
![Page 19: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/19.jpg)
4. EntityManager
void insert(Object parameter)
void update(Object parameter)
void delete(Object parameter)
Object load(Object parameter)
List list(Object parameter)
List list(Object parameter, String orderby)
List list(Object parameter, String orderby,
int rows)
19
![Page 20: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/20.jpg)
EntityManager 사용예
EntityManager entityManager = new EntityManager();
Hospital hospital = new Hospital();hospital.setHospitalid(12345);hospital.setName(“JCO병원”);hospital.setRegdttm(new Date());entityManager.insert(hospital);
hospital = entityManager.load(hospital);
hospital.setName(“JCO병원”);entityManager.update(hospital);
entityManager.delete(hospital);
20
![Page 21: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/21.jpg)
5. SQL Generation
• INSERT– 컬럼 중 auto_increment 로 선언된 컬럼은 insert 문
에서 제외
• UPDATE– Primary Key 가 아닌 컬럼들만 update– PK로 where 조건절 생성
• DELETE– parameter 객체에서 null 값이 아닌 field 로 where 조
건절 생성
• SELECT– parameter 객체에서 null 값이 아닌 field 로 where 조
건절 생성
21
![Page 22: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/22.jpg)
5-1. Insert문 생성
• 컬럼 중 auto_increment 로 선언된 컬럼은insert 문에서 제외
<생성되는 SQL>
INSERT INTO hospital (name, regdttm) VALUES (#{name}, #{regdttm})
22
![Page 23: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/23.jpg)
EntityManager.insert()
1: Class<?> clazz = object.getClass();
2: String statementName = PREFIX_INSERT +
3: clazz.getSimpleName();
4: if (!configuration.hasStatement(statementName)) {
5: addMappedStatement(
6: statementName,
7: new InsertSqlSource(sqlSourceParser,clazz),
8: SqlCommandType.INSERT,null);
9: }
10: getSqlSession().insert(statementName, object);
23
![Page 24: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/24.jpg)
InsertSqlSource
1: List<String> columnNames =
2: AnnotationUtil.getNonAutoIncrementColumnNames(clazz);
3: String sql = String.format(
4: “INSERT INTO %1$s ( %2$s ) VALUES ( %3$s ) ",
5: AnnotationUtil.getTableName(clazz),
6: StringUtil.join(columnNames, ","),
7: StringUtil.join(columnNames, "#{%1$s}",","));
8: parse(sqlSourceParser, sql, clazz);
24
![Page 25: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/25.jpg)
AnnotationUtil.getTableName
Table t = clazz.getAnnotation(Table.class);
return t.value();
25
![Page 26: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/26.jpg)
AnnotationUtil.getNonAutoIncrementColumnNames
1: List<String> names = new LinkedList<String>();
2: for (Field field : clazz.getDeclaredFields()) {
3: if (field.isAnnotationPresent(Column.class)) {
4: Column c = field.getAnnotation(Column.class);
5: if (!c.autoIncrement())
6: names.add("".equals(c.name()) ? field.getName():c.name());
7: }
8: }
9: return names;
26
![Page 27: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/27.jpg)
5-2. Update문 생성
• Primary Key 가 아닌 컬럼들만 update
• PK로 where 조건절 생성
<생성되는 SQL>
UPDATE hospital
SET name = #{name}, regdttm = #{regdttm}
WHERE hospitalid = #{hospitalid}
27
![Page 28: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/28.jpg)
EntityManager.update()
1: Class<?> clazz = object.getClass();
2: String statementName = PREFIX_UPDATE +
3: clazz.getSimpleName();
4: if (!configuration.hasStatement(statementName)) {
5: addMappedStatement(
6: statementName,
7: new UpdateSqlSource(sqlSourceParser,clazz),
8: SqlCommandType.UPDATE,null);
9: }
10: getSqlSession().update(statementName, object);
28
![Page 29: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/29.jpg)
UpdateSqlSource
String sql = String.format(
"UPDATE %1$s SET %2$s WHERE %3$s",
AnnotationUtil.getTableName(clazz),
StringUtil.join(
AnnotationUtil.getNonPrimaryKeyColumnNames(clazz),
"%1$s = #{%1$s}", ", "),
StringUtil.join(
AnnotationUtil.getPrimaryKeyColumnNames(clazz),
"%1$s = #{%1$s}"," AND "));
parse(sqlSourceParser, sql, clazz);
29
![Page 30: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/30.jpg)
AnnotationUtil.getNonPrimaryKeyColumnNames
1: List<String> names = new LinkedList<String>();
2: for (Field field : clazz.getDeclaredFields()) {
3: if (field.isAnnotationPresent(Column.class)) {
4: Column c = field.getAnnotation(Column.class);
5: if (!c.primaryKey())
6: names.add("".equals(c.name()) ? field.getName() :
7: c.name());
8: }
9: }
10: return names;
30
![Page 31: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/31.jpg)
AnnotationUtil.getPrimaryKeyColumnNames
List<String> names = new LinkedList<String>();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Column.class)) {
Column c = field.getAnnotation(Column.class);
if (c.primaryKey())
names.add("".equals(c.name()) ? field.getName() : c.name());
}
}
return names;
31
![Page 32: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/32.jpg)
5-3. Delete문 생성
• parameter 객체에서 null 값이 아닌 field 로where 조건절 생성
예)
Hospital hospital = new Hospital();
hospital.setName(“JCO병원”);
entityManager.delete(hospital);
<생성되는 SQL>
DELETE FROM hospital
WHERE name = #{name}
32
![Page 33: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/33.jpg)
EntityManager.delete()
1: Class<?> clazz = object.getClass();
2: String statementName = PREFIX_DELETE + clazz.getSimpleName();
3: if (!configuration.hasStatement(statementName)) {
4: addMappedStatement(
5: statementName,
6: new DeleteSqlSource(sqlSourceParser,clazz),
7: SqlCommandType.DELETE,null);
8: }
9: getSqlSession().delete(statementName, object);
33
![Page 34: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/34.jpg)
DeleteSqlSource
1: public DeleteSqlSource(SqlSourceBuilder sqlSourceParser,
2: Class<?> clazz) {
3: super(sqlSourceParser);
4: staticSql = "DELETE FROM”
5: +AnnotationUtil.getTableName(clazz);
6: }
7: public BoundSql getBoundSql(Object parameterObject) {
8: String sql = staticSql + " WHERE " +
9: StringUtil.join(
10: AnnotationUtil.getNotNullColumnNames(parameterObject),
11: "%1$s = #{%1$s}"," AND ");
12: return getBoundSql(sql,parameterObject);
13: }
34
![Page 35: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/35.jpg)
5-4. Select문 생성
• parameter 객체에서 null 값이 아닌 field 로 where 조건절 생성
예)
Hospital hospital = new Hospital();
hospital.setName(“JCO병원”);
hospital = (Hospital)entityManager.load(hospital);
<생성되는 SQL>
SELECT hospitalid, name, regdttm
FROM hospital
WHERE name = #{name}
35
![Page 36: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/36.jpg)
EntityManager.load()
1: Class<?> clazz = object.getClass();
2: String statementName = PREFIX_LOAD + clazz.getSimpleName();
3: if (!configuration.hasStatement(statementName)) {
4: addMappedStatement(statementName,
5: new SelectOneSqlSource(sqlSourceParser,clazz),
6: SqlCommandType.SELECT,clazz);
7: }
8: Object result = getSqlSession().selectOne(statementName, object);
9: if (result != null)
10: BeanUtils.copyProperties(result, object);
11: return result;
36
![Page 37: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/37.jpg)
SelectOneSqlSource
1: public SelectOneSqlSource(SqlSourceBuilder sqlSourceParser, Class<?> clazz) {
2: super(sqlSourceParser);
3: staticSql = String.format("SELECT %1$s FROM %2$s ",
4: StringUtil.join(AnnotationUtil.getColumnNames(clazz),", "),
5: AnnotationUtil.getTableName(clazz));
6: }
7:
8: public BoundSql getBoundSql(Object parameterObject) {
9: String sql = staticSql + " WHERE " +
10: StringUtil.join(
11: AnnotationUtil.getNotNullColumnNames(parameterObject),
12: "%1$s = #{%1$s}"," AND ") +
13: " LIMIT 1";
14: return getBoundSql(sql,parameterObject);
15: }
37
![Page 38: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/38.jpg)
복습
1. Table 생성2. Annotation 정의3. Mapping class 생성4. EntityManager 작성 – CRUD interface5. SQL Generation 클래스 작성
– InsertSqlSource– UpdateSqlSource– DeleteSqlSource– SelectOneSqlSource– SelectListSqlSource
38
![Page 39: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/39.jpg)
Effect
• 비타민MD 사이트에 일부 적용
• 만약 전체 적용한다면
69% SQL문 제거 가능
39
SQL 적용 전 적용 후
insert 112 7
update 80 2
delete 79 0
select 327 176
총 598 185
![Page 40: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/40.jpg)
Future Work
• Annotation 추가
– Like 구문 지원
– DDL 상의 default 값, not null 등의 constraint 지원
• Transaction
• Caching
• Oracle, MSSQL, DB2 등 다른 DBMS 지원
40
![Page 42: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/42.jpg)
Do It Yourself and Have Fun.
42
![Page 43: Java Annotation과 MyBatis로 나만의 ORM Framework을 만들어보자](https://reader030.fdocuments.net/reader030/viewer/2022020108/5a6d23f27f8b9a0a428b4db7/html5/thumbnails/43.jpg)
이 저작물은 크리에이티브 커먼스 코리아 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
This work is Licensed under Creative Commons Korea Attribution 2.0 License.