orm을 맞이하는 우리의 자세

42
ORM 을 맞이하는 우리의 자세 정병태

Upload: -

Post on 12-Apr-2017

1.698 views

Category:

Software


3 download

TRANSCRIPT

Page 1: ORM을 맞이하는 우리의 자세

ORM 을 맞이하는 우리의 자세

정병태

Page 2: ORM을 맞이하는 우리의 자세

랑겔한스 : 정병태

- Web Developer

- OKKY.KR Contributor

- https://github.com/1angerhans - http://okky.kr/user/info/26138 - [email protected]

Page 3: ORM을 맞이하는 우리의 자세

‘나는 SQL 이 싫어요.’

Page 4: ORM을 맞이하는 우리의 자세

ORMObject Relational Mapping

Page 5: ORM을 맞이하는 우리의 자세

– Wikipedia 인용

“Object-relational mapping (ORM, O/RM, and O/R mapping) in computer science is a programming technique for converting data between

incompatible type systems in object-oriented programming languages.”

Page 6: ORM을 맞이하는 우리의 자세

– Wikipedia 인용

“객체 관계 매핑(Object-relational mapping; ORM)은 데이터베이스와 객체 지향 프로그래밍 언어 간의 호환되지 않는 데이터를 변환하는 프로그래밍 기법이다.”

Page 7: ORM을 맞이하는 우리의 자세

Object-relational impedance mismatch

- Data type differences - Structural and integrity differences - Manipulative difference - Transactional differences

https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch

Page 8: ORM을 맞이하는 우리의 자세

문제의 해결 Without ORM

Page 9: ORM을 맞이하는 우리의 자세

현실의 문제 #1

Page 10: ORM을 맞이하는 우리의 자세

Vo, DTO 그리고 Table들

Page 11: ORM을 맞이하는 우리의 자세

D.D.DDomain Driven Design

Page 12: ORM을 맞이하는 우리의 자세

Domain Entity 설계

Page 13: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_MSG ( F_GRP_ID INT(6) NOT NULL PRIMARY KEY , PTN_ID INT(6) , PRIORITY INT(6) , JOB_CODE INT(6) , FLAG_PRO INT(6) , CHAINNUM INT(6) , MASSNUM INT(6) , USERID VARCHAR(20) , CPCODE VARCHAR(20) , QTCODE VARCHAR(20) , MSGSEPER CHAR(1) , MSG_CNT INT(6) , CNTPSEC INT(6) ,

흔한 Legacy Table

Page 14: ORM을 맞이하는 우리의 자세

Minimization

Page 15: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

AUTH_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

TEL VARCHAR(12) ,

CELL VARCHAR(12) ,

OFFICE_TEL VARCHAR(12) ,

EMAIL VARCHAR(200) ,

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200) ,

COMPANY_NAME VARCHAR(20) ,

QUARTER_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

MILEAGE INT(12) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

User

Contact

Company

Domains

Auth

Mileage

Page 16: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

Page 17: ORM을 맞이하는 우리의 자세

public class User { Long seq; String userid; String userpass; String username; Date regDate;

Company company; Address address; Contact contact; Mileage mileage;

List<Auth> authorities;

// Getter & Setter }

public class Company { … }

public class Address { … }

public class Contact { … }

public class Mileage { … }

public class Auth { … }

Page 18: ORM을 맞이하는 우리의 자세

현실의 문제 #2

Page 19: ORM을 맞이하는 우리의 자세

DBA

Page 20: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

Page 21: ORM을 맞이하는 우리의 자세

DBA 들이 나를 향해 이렇게 외친다.

Page 22: ORM을 맞이하는 우리의 자세

public class MSG {

int grpnum; int chainnum; String userid; String usernm; String cpcode; String qtcode; String title; String sndTitle; String cComment; String dstaddr; String callback; String msgTemplet; String reservData;

흔한 Legacy Model

Page 23: ORM을 맞이하는 우리의 자세

Mybatis Association

Page 24: ORM을 맞이하는 우리의 자세

<select id="selectOne" resultMap=“userMap">

select u.seq, u.userid, u.pass, u.name, u.tel, u.cel, u.email, u.company_name, u.zipcode, u.address_01, u.address_02 …. from tbl_user u where u.seq = #{seq}

</select>

Mybatis

Page 25: ORM을 맞이하는 우리의 자세

Mybatis Association<resultMap id="userMap" type=“User">

<id jdbcType="INTEGER" property="seq" column="seq"/> <result jdbcType="VARCHAR" property="userid" column="userid"/> <result jdbcType="VARCHAR" property="pass" column="pass"/>

<association property="company" javaType="Company" > <result jdbcType="VARCHAR" property=“company_name" column="cpname"/> </association>

<association property="contact" javaType="Contact" > <result jdbcType="VARCHAR" property=“company_name" column="cpname"/> </association>

<association property="address" javaType="Address" > <result jdbcType="VARCHAR" property=“zopcode" column=“zopcode"/> <result jdbcType="VARCHAR" property=“address_01” column=“address_01"/> <result jdbcType="VARCHAR" property=“address_01” column="address_01"/> </association>

<collection property="authorities" select="selectUserAuthList" fetchType="lazy" column="{seq=seq}" />

</resultMap>

Page 26: ORM을 맞이하는 우리의 자세

– 미상

“인간의 욕심은 끝이 없고, 같은 실수를 반복한다.”

Page 27: ORM을 맞이하는 우리의 자세

With ORM

Page 28: ORM을 맞이하는 우리의 자세

Hibernate

Page 29: ORM을 맞이하는 우리의 자세

@Entity@Table( name = “TBL_USER" )public class User { Integer seq; String userid; String userpass; String username; Date regDate;

Company company; Address address; Contact contact; Mileage mileage;

List<Auth> authorities;

// Getter & Setter

@Id@GeneratedValue(generator="increment")@GenericGenerator(name="increment", strategy = “increment”)@Column(name = “SEQ”)

Long getSeq() { return seq;

}

}

@Entity@Table( name = “TBL_COMPANY" )public class Company { … }

@Entity@Table( name = “TBL_ADDRESS" )public class Address { … }

@Entity@Table( name = “TBL_CONTACT" )public class Contact { … }

@Entity@Table( name = “TBL_MILEAGE" )public class Mileage { … }

@Entity@Table( name = “TBL_AUTH" )public class Auth { … }

Page 30: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

CREATE TABLE TBL_COMPANY (

SEQ INT(6) NOT NULL PRIMARY KEY ,

COMPANY_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

REG_DATE DATE

);

CREATE TABLE TBL_AUTH (

SEQ INT(6) NOT NULL PRIMARY KEY ,

ROLE VARCHAR(20)

);

CREATE TABLE TBL_ADDRESS (

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200)

);

CREATE TABLE TBL_CONTACT (

SEQ INT(6) NOT NULL PRIMARY KEY ,

TEL VARCHAR(12) ,

CELL VARCHAR(12)

);

CREATE TABLE TBL_MILEAGE (

SEQ INT(6) NOT NULL PRIMARY KEY ,

POINT INT(12)

);

Page 31: ORM을 맞이하는 우리의 자세

DBA 들이 나를 향해 이렇게 외친다.

Page 32: ORM을 맞이하는 우리의 자세

CREATE TABLE TBL_USER (

SEQ INT(6) NOT NULL PRIMARY KEY ,

USER_TYPE VARCHAR(20) ,

AUTH_TYPE VARCHAR(20) ,

USERID VARCHAR(20) ,

NAME VARCHAR(20) ,

PASS VARCHAR(20) ,

TEL VARCHAR(12) ,

CELL VARCHAR(12) ,

OFFICE_TEL VARCHAR(12) ,

EMAIL VARCHAR(200) ,

ZIPCODE VARCHAR(7) ,

ADDRESS_01 VARCHAR(200) ,

ADDRESS_02 VARCHAR(200) ,

COMPANY_NAME VARCHAR(20) ,

QUARTER_NAME VARCHAR(20) ,

STATUS VARCHAR(20) ,

MILEAGE INT(12) ,

REG_DATE DATE ,

PASS_CHG_DATE DATE ,

PASS_FAIL_CNT INT(6)

);

User

Contact

Company

Domains

Auth

Mileage

Page 33: ORM을 맞이하는 우리의 자세

@Entity@Table( name = “TBL_USER" )public class User {

@Id@GeneratedValue(generator="increment")@GenericGenerator(name="increment", strategy = “increment”)@Column(name = “SEQ”)

Integer seq;

@Column(name = “USERID”) String userid;

@Embedded

Company company;

@Embedded

Address address;

@Embedded

Contact contact;

@OneToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY) Mileage mileage;

@OneToMany( cascade = CascadeType.ALL, fetch = FetchType.LAZY) List<Auth> authorities;

}

@Embeddable

public class Company { … }

@Embeddable

public class Address { … }

@Embeddable

public class Contact { … }

@Embeddable

public class Mileage { … }

@Embeddable

public class Auth { … }

Page 34: ORM을 맞이하는 우리의 자세

Criteria

Page 35: ORM을 맞이하는 우리의 자세

Criteria

Criteria criteria = session.createCriteria(User.class);

criteria.add(Restrictions.eq("seq", seq))

.setProjection(

Projections.projectionList()

.add(Projections.property(“zipcode"))

.add(Projections.property(“address_01"))

.add(Projections.property(“address_02")))

.setResultTransformer(

Transformers.aliasToBean(Address.class));

Address address = criteria.uniqueResult();

Page 36: ORM을 맞이하는 우리의 자세

HQL

Page 37: ORM을 맞이하는 우리의 자세

HQL

Address address = session.createQuery(“select u.zipcode,

u.address_01, u.address_02 from User u where seq = :seq”, )

.setParameter("seq", seq)

.setResultTransformer(

Transformers.aliasToBean(Address.class))

.uniqueResult();

Page 38: ORM을 맞이하는 우리의 자세

ORM 에 대한 단상

• Legacy DB 도 충분히 도입 가능하다.

• ORM을 염두한 디자인을 적용할 경우 생산성이 급격히 좋아진다.

• Criteria는 학습이 쉽지 않다.

• HQL을 쓸 때면 뭔가 손해보는 기분.. (방언 처리 라고는 하지만..)

• 퍼포먼스는 사실상 문제 없다.

• SQL Layer가 빠져야돼.

Page 39: ORM을 맞이하는 우리의 자세

ORM 은 우리가 가지고 있는 문제를 해결한

‘결과’가 아닌

더욱 나은 방향으로 가기 위한 ‘과정’ 입니다.

– 저

Page 40: ORM을 맞이하는 우리의 자세

No SQL

Page 41: ORM을 맞이하는 우리의 자세

SQL이 필요 없다고 RDBMS가 필요 없는건 아닐껍니다.

Page 42: ORM을 맞이하는 우리의 자세

공유의 시간